Loading app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt +36 −19 Original line number Diff line number Diff line Loading @@ -232,12 +232,32 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { fetchAppTracker(it) observeDownloadList() observeDownloadStatus(binding.root) updateInstallButton(it) stopLoadingUI() collectState() } @SuppressLint("SetTextI18n") private fun updateInstallButton(application: Application) { binding.downloadInclude.apply { installButton.disableInstallButton(R.string.install) installButton.text = "" progressBarInstall.visibility = View.VISIBLE } if (!isFreeOrAlreadyPurchased(application)) { appInfoFetchViewModel.isAppPurchased(application).observe(viewLifecycleOwner) { binding.downloadInclude.progressBarInstall.visibility = View.GONE observeDownloadStatus(binding.root) } return } binding.downloadInclude.progressBarInstall.visibility = View.GONE observeDownloadStatus(binding.root) } private fun collectState() { collectShareVisibilityState() collectAppContentRatingState() Loading Loading @@ -585,13 +605,15 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { /* Remove trailing slash (if present) that can become part of the packageName */ val packageName = args.packageName.run { if (endsWith('/')) dropLast(1) else this } applicationViewModel.loadData( val applicationLoadingParams = ApplicationLoadingParams( args.id, packageName, origin, isFdroidDeepLink, authObjectList ) { authObjectList, args.isPurchased ) applicationViewModel.loadData(applicationLoadingParams) { clearAndRestartGPlayLogin() true } Loading Loading @@ -783,7 +805,6 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { } } @SuppressLint("SetTextI18n") private fun handleUnavaiable( installButton: MaterialButton, application: Application, Loading @@ -791,28 +812,21 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { appSize: MaterialTextView ) { installButton.apply { installButton.disableInstallButton(R.string.install) installButton.text = "" binding.downloadInclude.progressBarInstall.visibility = View.VISIBLE appInfoFetchViewModel.isAppPurchased(application).observe(viewLifecycleOwner) { binding.downloadInclude.progressBarInstall.visibility = View.GONE enableInstallButton(R.string.install) text = when { mainActivityViewModel.checkUnsupportedApplication(application) -> getString(R.string.not_available) application.isFree || application.isPurchased -> getString(R.string.install) isFreeOrAlreadyPurchased(application) -> getString(R.string.install) else -> application.price } } setOnClickListener { if (mainActivityViewModel.checkUnsupportedApplication(application, activity)) { return@setOnClickListener } applicationIcon?.let { if (application.isFree || application.isPurchased) { if (isFreeOrAlreadyPurchased(application)) { disableInstallButton(R.string.cancel) installApplication(application) } else { Loading @@ -825,6 +839,9 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { appSize.visibility = View.VISIBLE } private fun isFreeOrAlreadyPurchased(application: Application) = application.isFree || application.isPurchased private fun handleInstallClickForPaidApp(application: Application) { if (!mainActivityViewModel.shouldShowPaidAppsSnackBar(application)) { ApplicationDialogFragment( Loading app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt +44 −13 Original line number Diff line number Diff line Loading @@ -72,45 +72,66 @@ class ApplicationViewModel @Inject constructor( val appContentRatingState = _appContentRatingState.asStateFlow() fun loadData( id: String, packageName: String, origin: Origin, isFdroidLink: Boolean, authObjectList: List<AuthObject>, params: ApplicationLoadingParams, retryBlock: (failedObjects: List<AuthObject>) -> Boolean, ) { if (isFdroidLink) { getCleanapkAppDetails(packageName) if (params.isFdroidDeepLink) { getCleanapkAppDetails(params.packageName) return } val gPlayObj = authObjectList.find { it is AuthObject.GPlayAuth } val gPlayObj = params.authObjectList.find { it is AuthObject.GPlayAuth } /* * If user is viewing only open source apps, auth object list will not have * GPlayAuth, it will only have CleanApkAuth. */ if (gPlayObj == null && origin == Origin.GPLAY) { if (gPlayObj == null && params.origin == Origin.GPLAY) { _errorMessageLiveData.postValue(R.string.gplay_data_for_oss) return } super.onLoadData(authObjectList, { successAuthList, _ -> super.onLoadData(params.authObjectList, { successAuthList, _ -> successAuthList.find { it is AuthObject.GPlayAuth }?.run { getApplicationDetails(id, packageName, result.data!! as AuthData, origin) val authData = result.data as? AuthData // Usually authdata won't be null, null check is added to avoid forcefully unwrapping if (authData == null) { _errorMessageLiveData.postValue(R.string.data_load_error) return@onLoadData } getApplicationDetails( params.appId, params.packageName, params.isPurchased, authData, params.origin ) return@onLoadData } successAuthList.find { it is AuthObject.CleanApk }?.run { getApplicationDetails(id, packageName, AuthData("", ""), origin) getApplicationDetails( params.appId, params.packageName, params.isPurchased, AuthData("", ""), params.origin ) return@onLoadData } }, retryBlock) } fun getApplicationDetails(id: String, packageName: String, authData: AuthData, origin: Origin) { fun getApplicationDetails( id: String, packageName: String, isPurchased: Boolean, authData: AuthData, origin: Origin ) { viewModelScope.launch(Dispatchers.IO) { try { val appData = Loading @@ -120,6 +141,7 @@ class ApplicationViewModel @Inject constructor( authData, origin ) appData.first.isPurchased = isPurchased applicationLiveData.postValue(appData) updateShareVisibilityState(appData.first.shareUri.toString()) Loading Loading @@ -247,3 +269,12 @@ sealed class ShareButtonVisibilityState { object Visible : ShareButtonVisibilityState() object Hidden : ShareButtonVisibilityState() } data class ApplicationLoadingParams( val appId: String, val packageName: String, val origin: Origin, val isFdroidDeepLink: Boolean, val authObjectList: List<AuthObject>, val isPurchased: Boolean ) app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListRVAdapter.kt +6 −3 Original line number Diff line number Diff line Loading @@ -258,7 +258,8 @@ class ApplicationListRVAdapter( searchApp._id, searchApp.origin, catText, searchApp.isGplayReplaced searchApp.isGplayReplaced, searchApp.isPurchased ) } R.id.searchFragment -> { Loading @@ -267,7 +268,8 @@ class ApplicationListRVAdapter( searchApp._id, searchApp.origin, catText, searchApp.isGplayReplaced searchApp.isGplayReplaced, searchApp.isPurchased ) } R.id.updatesFragment -> { Loading @@ -276,7 +278,8 @@ class ApplicationListRVAdapter( searchApp._id, searchApp.origin, catText, searchApp.isGplayReplaced searchApp.isGplayReplaced, searchApp.isPurchased ) } else -> null Loading app/src/main/java/foundation/e/apps/ui/home/model/HomeChildRVAdapter.kt +2 −1 Original line number Diff line number Diff line Loading @@ -97,7 +97,8 @@ class HomeChildRVAdapter( homeApp._id, homeApp.origin, homeApp.category, homeApp.isGplayReplaced homeApp.isGplayReplaced, homeApp.isPurchased ) holder.itemView.findNavController().navigate(action) } Loading app/src/main/res/layout/fragment_application_download.xml +1 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ android:id="@+id/progressLayout" android:layout_width="0dp" android:layout_height="wrap_content" android:visibility="invisible" app:layout_constraintBottom_toBottomOf="@id/installButton" app:layout_constraintTop_toTopOf="parent" app:layout_constraintLeft_toLeftOf="parent" Loading Loading
app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt +36 −19 Original line number Diff line number Diff line Loading @@ -232,12 +232,32 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { fetchAppTracker(it) observeDownloadList() observeDownloadStatus(binding.root) updateInstallButton(it) stopLoadingUI() collectState() } @SuppressLint("SetTextI18n") private fun updateInstallButton(application: Application) { binding.downloadInclude.apply { installButton.disableInstallButton(R.string.install) installButton.text = "" progressBarInstall.visibility = View.VISIBLE } if (!isFreeOrAlreadyPurchased(application)) { appInfoFetchViewModel.isAppPurchased(application).observe(viewLifecycleOwner) { binding.downloadInclude.progressBarInstall.visibility = View.GONE observeDownloadStatus(binding.root) } return } binding.downloadInclude.progressBarInstall.visibility = View.GONE observeDownloadStatus(binding.root) } private fun collectState() { collectShareVisibilityState() collectAppContentRatingState() Loading Loading @@ -585,13 +605,15 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { /* Remove trailing slash (if present) that can become part of the packageName */ val packageName = args.packageName.run { if (endsWith('/')) dropLast(1) else this } applicationViewModel.loadData( val applicationLoadingParams = ApplicationLoadingParams( args.id, packageName, origin, isFdroidDeepLink, authObjectList ) { authObjectList, args.isPurchased ) applicationViewModel.loadData(applicationLoadingParams) { clearAndRestartGPlayLogin() true } Loading Loading @@ -783,7 +805,6 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { } } @SuppressLint("SetTextI18n") private fun handleUnavaiable( installButton: MaterialButton, application: Application, Loading @@ -791,28 +812,21 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { appSize: MaterialTextView ) { installButton.apply { installButton.disableInstallButton(R.string.install) installButton.text = "" binding.downloadInclude.progressBarInstall.visibility = View.VISIBLE appInfoFetchViewModel.isAppPurchased(application).observe(viewLifecycleOwner) { binding.downloadInclude.progressBarInstall.visibility = View.GONE enableInstallButton(R.string.install) text = when { mainActivityViewModel.checkUnsupportedApplication(application) -> getString(R.string.not_available) application.isFree || application.isPurchased -> getString(R.string.install) isFreeOrAlreadyPurchased(application) -> getString(R.string.install) else -> application.price } } setOnClickListener { if (mainActivityViewModel.checkUnsupportedApplication(application, activity)) { return@setOnClickListener } applicationIcon?.let { if (application.isFree || application.isPurchased) { if (isFreeOrAlreadyPurchased(application)) { disableInstallButton(R.string.cancel) installApplication(application) } else { Loading @@ -825,6 +839,9 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { appSize.visibility = View.VISIBLE } private fun isFreeOrAlreadyPurchased(application: Application) = application.isFree || application.isPurchased private fun handleInstallClickForPaidApp(application: Application) { if (!mainActivityViewModel.shouldShowPaidAppsSnackBar(application)) { ApplicationDialogFragment( Loading
app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt +44 −13 Original line number Diff line number Diff line Loading @@ -72,45 +72,66 @@ class ApplicationViewModel @Inject constructor( val appContentRatingState = _appContentRatingState.asStateFlow() fun loadData( id: String, packageName: String, origin: Origin, isFdroidLink: Boolean, authObjectList: List<AuthObject>, params: ApplicationLoadingParams, retryBlock: (failedObjects: List<AuthObject>) -> Boolean, ) { if (isFdroidLink) { getCleanapkAppDetails(packageName) if (params.isFdroidDeepLink) { getCleanapkAppDetails(params.packageName) return } val gPlayObj = authObjectList.find { it is AuthObject.GPlayAuth } val gPlayObj = params.authObjectList.find { it is AuthObject.GPlayAuth } /* * If user is viewing only open source apps, auth object list will not have * GPlayAuth, it will only have CleanApkAuth. */ if (gPlayObj == null && origin == Origin.GPLAY) { if (gPlayObj == null && params.origin == Origin.GPLAY) { _errorMessageLiveData.postValue(R.string.gplay_data_for_oss) return } super.onLoadData(authObjectList, { successAuthList, _ -> super.onLoadData(params.authObjectList, { successAuthList, _ -> successAuthList.find { it is AuthObject.GPlayAuth }?.run { getApplicationDetails(id, packageName, result.data!! as AuthData, origin) val authData = result.data as? AuthData // Usually authdata won't be null, null check is added to avoid forcefully unwrapping if (authData == null) { _errorMessageLiveData.postValue(R.string.data_load_error) return@onLoadData } getApplicationDetails( params.appId, params.packageName, params.isPurchased, authData, params.origin ) return@onLoadData } successAuthList.find { it is AuthObject.CleanApk }?.run { getApplicationDetails(id, packageName, AuthData("", ""), origin) getApplicationDetails( params.appId, params.packageName, params.isPurchased, AuthData("", ""), params.origin ) return@onLoadData } }, retryBlock) } fun getApplicationDetails(id: String, packageName: String, authData: AuthData, origin: Origin) { fun getApplicationDetails( id: String, packageName: String, isPurchased: Boolean, authData: AuthData, origin: Origin ) { viewModelScope.launch(Dispatchers.IO) { try { val appData = Loading @@ -120,6 +141,7 @@ class ApplicationViewModel @Inject constructor( authData, origin ) appData.first.isPurchased = isPurchased applicationLiveData.postValue(appData) updateShareVisibilityState(appData.first.shareUri.toString()) Loading Loading @@ -247,3 +269,12 @@ sealed class ShareButtonVisibilityState { object Visible : ShareButtonVisibilityState() object Hidden : ShareButtonVisibilityState() } data class ApplicationLoadingParams( val appId: String, val packageName: String, val origin: Origin, val isFdroidDeepLink: Boolean, val authObjectList: List<AuthObject>, val isPurchased: Boolean )
app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListRVAdapter.kt +6 −3 Original line number Diff line number Diff line Loading @@ -258,7 +258,8 @@ class ApplicationListRVAdapter( searchApp._id, searchApp.origin, catText, searchApp.isGplayReplaced searchApp.isGplayReplaced, searchApp.isPurchased ) } R.id.searchFragment -> { Loading @@ -267,7 +268,8 @@ class ApplicationListRVAdapter( searchApp._id, searchApp.origin, catText, searchApp.isGplayReplaced searchApp.isGplayReplaced, searchApp.isPurchased ) } R.id.updatesFragment -> { Loading @@ -276,7 +278,8 @@ class ApplicationListRVAdapter( searchApp._id, searchApp.origin, catText, searchApp.isGplayReplaced searchApp.isGplayReplaced, searchApp.isPurchased ) } else -> null Loading
app/src/main/java/foundation/e/apps/ui/home/model/HomeChildRVAdapter.kt +2 −1 Original line number Diff line number Diff line Loading @@ -97,7 +97,8 @@ class HomeChildRVAdapter( homeApp._id, homeApp.origin, homeApp.category, homeApp.isGplayReplaced homeApp.isGplayReplaced, homeApp.isPurchased ) holder.itemView.findNavController().navigate(action) } Loading
app/src/main/res/layout/fragment_application_download.xml +1 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ android:id="@+id/progressLayout" android:layout_width="0dp" android:layout_height="wrap_content" android:visibility="invisible" app:layout_constraintBottom_toBottomOf="@id/installButton" app:layout_constraintTop_toTopOf="parent" app:layout_constraintLeft_toLeftOf="parent" Loading