Loading app/src/main/java/foundation/e/apps/AppInfoFetchViewModel.kt +9 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ import com.aurora.gplayapi.data.models.AuthData import com.google.gson.Gson import dagger.hilt.android.lifecycle.HiltViewModel import foundation.e.apps.api.cleanapk.blockedApps.BlockedAppRepository import foundation.e.apps.api.faultyApps.FaultyAppRepository import foundation.e.apps.api.fdroid.FdroidRepository import foundation.e.apps.api.fdroid.models.FdroidEntity import foundation.e.apps.api.fused.data.FusedApp Loading @@ -27,6 +28,7 @@ import javax.inject.Inject class AppInfoFetchViewModel @Inject constructor( private val fdroidRepository: FdroidRepository, private val gPlayAPIRepository: GPlayAPIRepository, private val faultyAppRepository: FaultyAppRepository, private val dataStoreModule: DataStoreModule, private val blockedAppRepository: BlockedAppRepository, private val gson: Gson Loading Loading @@ -89,4 +91,11 @@ class AppInfoFetchViewModel @Inject constructor( fun isAppInBlockedList(fusedApp: FusedApp): Boolean { return blockedAppRepository.getBlockedAppPackages().contains(fusedApp.package_name) } fun isAppFaulty(fusedApp: FusedApp) = liveData<Pair<Boolean, String>> { val faultyApp = faultyAppRepository.getAllFaultyApps() .find { faultyApp -> faultyApp.packageName.contentEquals(fusedApp.package_name) } val faultyAppResult = Pair(faultyApp != null, faultyApp?.error ?: "") emit(faultyAppResult) } } app/src/main/java/foundation/e/apps/api/faultyApps/FaultyAppRepository.kt +6 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ package foundation.e.apps.api.faultyApps import foundation.e.apps.api.fused.data.FusedApp import javax.inject.Inject import javax.inject.Singleton Loading @@ -38,4 +39,9 @@ class FaultyAppRepository @Inject constructor(private val faultyAppDao: FaultyAp suspend fun deleteFaultyAppByPackageName(packageName: String) { faultyAppDao.deleteFaultyAppByPackageName(packageName) } suspend fun removeFaultyApps(fusedApps: List<FusedApp>): List<FusedApp> { val faultyAppsPackageNames = getAllFaultyApps().map { it.packageName } return fusedApps.filter { !faultyAppsPackageNames.contains(it.package_name) } } } app/src/main/java/foundation/e/apps/applicationlist/model/ApplicationListRVAdapter.kt +50 −6 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ import foundation.e.apps.api.fused.FusedAPIInterface import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.applicationlist.ApplicationListFragmentDirections import foundation.e.apps.databinding.ApplicationListItemBinding import foundation.e.apps.manager.pkg.InstallerService import foundation.e.apps.search.SearchFragmentDirections import foundation.e.apps.updates.UpdatesFragmentDirections import foundation.e.apps.utils.enums.Origin Loading Loading @@ -243,19 +244,58 @@ class ApplicationListRVAdapter( private fun ApplicationListItemBinding.handleInstallationIssue( view: View, searchApp: FusedApp, ) { progressBarInstall.visibility = View.GONE if (lifecycleOwner == null) { return } appInfoFetchViewModel.isAppFaulty(searchApp).observe(lifecycleOwner!!) { updateInstallButton(it, view, searchApp) } } private fun ApplicationListItemBinding.updateInstallButton( faultyAppResult: Pair<Boolean, String>, view: View, searchApp: FusedApp ) { installButton.apply { isEnabled = true text = view.context.getString(R.string.retry) setTextColor(context.getColor(R.color.colorAccent)) isEnabled = !faultyAppResult.first text = getInstallationIssueText(faultyAppResult, view) strokeColor = getStrokeColor(isEnabled, view) setButtonTextColor(isEnabled) backgroundTintList = ContextCompat.getColorStateList(view.context, android.R.color.transparent) strokeColor = ContextCompat.getColorStateList(view.context, R.color.colorAccent) setOnClickListener { installApplication(searchApp, appIcon) } } progressBarInstall.visibility = View.GONE } private fun MaterialButton.getInstallationIssueText( faultyAppResult: Pair<Boolean, String>, view: View ) = if (faultyAppResult.second.contentEquals(InstallerService.INSTALL_FAILED_UPDATE_INCOMPATIBLE)) view.context.getText(R.string.update) else view.context.getString(R.string.retry) private fun MaterialButton.getStrokeColor( isEnabled: Boolean, view: View ) = if (isEnabled) { ContextCompat.getColorStateList(view.context, R.color.colorAccent) } else { ContextCompat.getColorStateList(view.context, R.color.light_grey) } private fun MaterialButton.setButtonTextColor(isEnabled: Boolean) = if (isEnabled) { setTextColor(context.getColor(R.color.colorAccent)) } else { setTextColor(context.getColor(R.color.light_grey)) } private fun ApplicationListItemBinding.handleBlocked(view: View) { Loading Loading @@ -455,7 +495,11 @@ class ApplicationListRVAdapter( if (searchApp.is_pwa) { mainActivityViewModel.launchPwa(searchApp) } else { context.startActivity(mainActivityViewModel.getLaunchIntentForPackageName(searchApp.package_name)) context.startActivity( mainActivityViewModel.getLaunchIntentForPackageName( searchApp.package_name ) ) } } } Loading app/src/main/java/foundation/e/apps/manager/pkg/InstallerService.kt +1 −1 Original line number Diff line number Diff line Loading @@ -50,7 +50,7 @@ class InstallerService : Service() { companion object { const val TAG = "InstallerService" private const val INSTALL_FAILED_UPDATE_INCOMPATIBLE = "INSTALL_FAILED_UPDATE_INCOMPATIBLE" const val INSTALL_FAILED_UPDATE_INCOMPATIBLE = "INSTALL_FAILED_UPDATE_INCOMPATIBLE" } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) Loading app/src/main/java/foundation/e/apps/search/SearchFragment.kt +16 −1 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package foundation.e.apps.search import android.app.Activity import android.content.Context import android.database.MatrixCursor import android.os.Bundle import android.provider.BaseColumns Loading Loading @@ -295,6 +296,11 @@ class SearchFragment : refreshData(it) } } if (searchText.isEmpty() && (recyclerView?.adapter as ApplicationListRVAdapter).currentList.isEmpty()) { searchView?.requestFocus() showKeyboard() } } private fun shouldRefreshData() = Loading @@ -304,12 +310,15 @@ class SearchFragment : override fun onPause() { binding.shimmerLayout.stopShimmer() hideKeyboard(requireActivity()) super.onPause() } override fun onQueryTextSubmit(query: String?): Boolean { query?.let { text -> if (text.isNotEmpty()) { hideKeyboard(activity as Activity) } view?.requestFocus() searchHintLayout?.visibility = View.GONE shimmerLayout?.visibility = View.VISIBLE Loading Loading @@ -369,6 +378,12 @@ class SearchFragment : inputMethodManager.hideSoftInputFromWindow(view?.windowToken, 0) } private fun showKeyboard() { val imm = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY) } private fun populateSuggestionsAdapter(suggestions: List<SearchSuggestEntry>?) { val cursor = MatrixCursor(arrayOf(BaseColumns._ID, SUGGESTION_KEY)) suggestions?.let { Loading Loading
app/src/main/java/foundation/e/apps/AppInfoFetchViewModel.kt +9 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ import com.aurora.gplayapi.data.models.AuthData import com.google.gson.Gson import dagger.hilt.android.lifecycle.HiltViewModel import foundation.e.apps.api.cleanapk.blockedApps.BlockedAppRepository import foundation.e.apps.api.faultyApps.FaultyAppRepository import foundation.e.apps.api.fdroid.FdroidRepository import foundation.e.apps.api.fdroid.models.FdroidEntity import foundation.e.apps.api.fused.data.FusedApp Loading @@ -27,6 +28,7 @@ import javax.inject.Inject class AppInfoFetchViewModel @Inject constructor( private val fdroidRepository: FdroidRepository, private val gPlayAPIRepository: GPlayAPIRepository, private val faultyAppRepository: FaultyAppRepository, private val dataStoreModule: DataStoreModule, private val blockedAppRepository: BlockedAppRepository, private val gson: Gson Loading Loading @@ -89,4 +91,11 @@ class AppInfoFetchViewModel @Inject constructor( fun isAppInBlockedList(fusedApp: FusedApp): Boolean { return blockedAppRepository.getBlockedAppPackages().contains(fusedApp.package_name) } fun isAppFaulty(fusedApp: FusedApp) = liveData<Pair<Boolean, String>> { val faultyApp = faultyAppRepository.getAllFaultyApps() .find { faultyApp -> faultyApp.packageName.contentEquals(fusedApp.package_name) } val faultyAppResult = Pair(faultyApp != null, faultyApp?.error ?: "") emit(faultyAppResult) } }
app/src/main/java/foundation/e/apps/api/faultyApps/FaultyAppRepository.kt +6 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ package foundation.e.apps.api.faultyApps import foundation.e.apps.api.fused.data.FusedApp import javax.inject.Inject import javax.inject.Singleton Loading @@ -38,4 +39,9 @@ class FaultyAppRepository @Inject constructor(private val faultyAppDao: FaultyAp suspend fun deleteFaultyAppByPackageName(packageName: String) { faultyAppDao.deleteFaultyAppByPackageName(packageName) } suspend fun removeFaultyApps(fusedApps: List<FusedApp>): List<FusedApp> { val faultyAppsPackageNames = getAllFaultyApps().map { it.packageName } return fusedApps.filter { !faultyAppsPackageNames.contains(it.package_name) } } }
app/src/main/java/foundation/e/apps/applicationlist/model/ApplicationListRVAdapter.kt +50 −6 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ import foundation.e.apps.api.fused.FusedAPIInterface import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.applicationlist.ApplicationListFragmentDirections import foundation.e.apps.databinding.ApplicationListItemBinding import foundation.e.apps.manager.pkg.InstallerService import foundation.e.apps.search.SearchFragmentDirections import foundation.e.apps.updates.UpdatesFragmentDirections import foundation.e.apps.utils.enums.Origin Loading Loading @@ -243,19 +244,58 @@ class ApplicationListRVAdapter( private fun ApplicationListItemBinding.handleInstallationIssue( view: View, searchApp: FusedApp, ) { progressBarInstall.visibility = View.GONE if (lifecycleOwner == null) { return } appInfoFetchViewModel.isAppFaulty(searchApp).observe(lifecycleOwner!!) { updateInstallButton(it, view, searchApp) } } private fun ApplicationListItemBinding.updateInstallButton( faultyAppResult: Pair<Boolean, String>, view: View, searchApp: FusedApp ) { installButton.apply { isEnabled = true text = view.context.getString(R.string.retry) setTextColor(context.getColor(R.color.colorAccent)) isEnabled = !faultyAppResult.first text = getInstallationIssueText(faultyAppResult, view) strokeColor = getStrokeColor(isEnabled, view) setButtonTextColor(isEnabled) backgroundTintList = ContextCompat.getColorStateList(view.context, android.R.color.transparent) strokeColor = ContextCompat.getColorStateList(view.context, R.color.colorAccent) setOnClickListener { installApplication(searchApp, appIcon) } } progressBarInstall.visibility = View.GONE } private fun MaterialButton.getInstallationIssueText( faultyAppResult: Pair<Boolean, String>, view: View ) = if (faultyAppResult.second.contentEquals(InstallerService.INSTALL_FAILED_UPDATE_INCOMPATIBLE)) view.context.getText(R.string.update) else view.context.getString(R.string.retry) private fun MaterialButton.getStrokeColor( isEnabled: Boolean, view: View ) = if (isEnabled) { ContextCompat.getColorStateList(view.context, R.color.colorAccent) } else { ContextCompat.getColorStateList(view.context, R.color.light_grey) } private fun MaterialButton.setButtonTextColor(isEnabled: Boolean) = if (isEnabled) { setTextColor(context.getColor(R.color.colorAccent)) } else { setTextColor(context.getColor(R.color.light_grey)) } private fun ApplicationListItemBinding.handleBlocked(view: View) { Loading Loading @@ -455,7 +495,11 @@ class ApplicationListRVAdapter( if (searchApp.is_pwa) { mainActivityViewModel.launchPwa(searchApp) } else { context.startActivity(mainActivityViewModel.getLaunchIntentForPackageName(searchApp.package_name)) context.startActivity( mainActivityViewModel.getLaunchIntentForPackageName( searchApp.package_name ) ) } } } Loading
app/src/main/java/foundation/e/apps/manager/pkg/InstallerService.kt +1 −1 Original line number Diff line number Diff line Loading @@ -50,7 +50,7 @@ class InstallerService : Service() { companion object { const val TAG = "InstallerService" private const val INSTALL_FAILED_UPDATE_INCOMPATIBLE = "INSTALL_FAILED_UPDATE_INCOMPATIBLE" const val INSTALL_FAILED_UPDATE_INCOMPATIBLE = "INSTALL_FAILED_UPDATE_INCOMPATIBLE" } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) Loading
app/src/main/java/foundation/e/apps/search/SearchFragment.kt +16 −1 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package foundation.e.apps.search import android.app.Activity import android.content.Context import android.database.MatrixCursor import android.os.Bundle import android.provider.BaseColumns Loading Loading @@ -295,6 +296,11 @@ class SearchFragment : refreshData(it) } } if (searchText.isEmpty() && (recyclerView?.adapter as ApplicationListRVAdapter).currentList.isEmpty()) { searchView?.requestFocus() showKeyboard() } } private fun shouldRefreshData() = Loading @@ -304,12 +310,15 @@ class SearchFragment : override fun onPause() { binding.shimmerLayout.stopShimmer() hideKeyboard(requireActivity()) super.onPause() } override fun onQueryTextSubmit(query: String?): Boolean { query?.let { text -> if (text.isNotEmpty()) { hideKeyboard(activity as Activity) } view?.requestFocus() searchHintLayout?.visibility = View.GONE shimmerLayout?.visibility = View.VISIBLE Loading Loading @@ -369,6 +378,12 @@ class SearchFragment : inputMethodManager.hideSoftInputFromWindow(view?.windowToken, 0) } private fun showKeyboard() { val imm = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY) } private fun populateSuggestionsAdapter(suggestions: List<SearchSuggestEntry>?) { val cursor = MatrixCursor(arrayOf(BaseColumns._ID, SUGGESTION_KEY)) suggestions?.let { Loading