Loading app/src/main/java/foundation/e/apps/FdroidFetchViewModel.kt→app/src/main/java/foundation/e/apps/AppInfoFetchViewModel.kt +30 −2 Original line number Diff line number Diff line package foundation.e.apps import android.widget.TextView import androidx.lifecycle.LiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.liveData import androidx.lifecycle.viewModelScope import com.aurora.gplayapi.data.models.AuthData import com.google.gson.Gson import dagger.hilt.android.lifecycle.HiltViewModel import foundation.e.apps.api.fdroid.FdroidRepository import foundation.e.apps.api.fdroid.models.FdroidEntity import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.api.gplay.GPlayAPIRepository import foundation.e.apps.utils.enums.Origin import foundation.e.apps.utils.modules.DataStoreModule import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext Loading @@ -17,8 +23,11 @@ import javax.inject.Inject * */ @HiltViewModel class FdroidFetchViewModel @Inject constructor( private val fdroidRepository: FdroidRepository class AppInfoFetchViewModel @Inject constructor( private val fdroidRepository: FdroidRepository, private val gPlayAPIRepository: GPlayAPIRepository, private val dataStoreModule: DataStoreModule, private val gson: Gson ) : ViewModel() { private val fdroidEntries = mutableMapOf<String, FdroidEntity?>() Loading Loading @@ -55,4 +64,23 @@ class FdroidFetchViewModel @Inject constructor( } } } fun isAppPurchased(app: FusedApp): LiveData<Boolean> { return liveData { val authData = gson.fromJson(dataStoreModule.getAuthDataSync(), AuthData::class.java) try { gPlayAPIRepository.getDownloadInfo( app.package_name, app.latest_version_code, app.offer_type, authData ) app.isPurchased = true emit(true) } catch (e: Exception) { app.isPurchased = false emit(false) } } } } app/src/main/java/foundation/e/apps/api/fused/data/FusedApp.kt +1 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ data class FusedApp( val url: String = String(), var type: Type = Type.NATIVE, var privacyScore: Int = -1, var isPurchased: Boolean = false, /* * List of permissions from Exodus API. Loading app/src/main/java/foundation/e/apps/application/ApplicationFragment.kt +3 −3 Original line number Diff line number Diff line Loading @@ -44,7 +44,7 @@ import com.google.android.material.button.MaterialButton import com.google.android.material.snackbar.Snackbar import com.google.android.material.textview.MaterialTextView import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.FdroidFetchViewModel import foundation.e.apps.AppInfoFetchViewModel import foundation.e.apps.MainActivityViewModel import foundation.e.apps.PrivacyInfoViewModel import foundation.e.apps.R Loading Loading @@ -81,7 +81,7 @@ class ApplicationFragment : Fragment(R.layout.fragment_application) { private val applicationViewModel: ApplicationViewModel by viewModels() private val privacyInfoViewModel: PrivacyInfoViewModel by viewModels() private val fdroidFetchViewModel: FdroidFetchViewModel by viewModels() private val appInfoFetchViewModel: AppInfoFetchViewModel by viewModels() private val mainActivityViewModel: MainActivityViewModel by activityViewModels() private var applicationIcon: ImageView? = null Loading Loading @@ -147,7 +147,7 @@ class ApplicationFragment : Fragment(R.layout.fragment_application) { applicationIcon = appIcon appName.text = it.name appAuthor.text = it.author fdroidFetchViewModel.setAuthorNameIfNeeded(appAuthor, it) appInfoFetchViewModel.setAuthorNameIfNeeded(appAuthor, it) categoryTitle.text = it.category if (args.origin == Origin.CLEANAPK) { appIcon.load(CleanAPKInterface.ASSET_URL + it.icon_image_path) Loading app/src/main/java/foundation/e/apps/applicationlist/ApplicationListFragment.kt +3 −3 Original line number Diff line number Diff line Loading @@ -31,8 +31,8 @@ import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.AppInfoFetchViewModel import foundation.e.apps.AppProgressViewModel import foundation.e.apps.FdroidFetchViewModel import foundation.e.apps.MainActivityViewModel import foundation.e.apps.PrivacyInfoViewModel import foundation.e.apps.R Loading Loading @@ -62,7 +62,7 @@ class ApplicationListFragment : Fragment(R.layout.fragment_application_list), Fu private val viewModel: ApplicationListViewModel by viewModels() private val privacyInfoViewModel: PrivacyInfoViewModel by viewModels() private val fdroidFetchViewModel: FdroidFetchViewModel by viewModels() private val appInfoFetchViewModel: AppInfoFetchViewModel by viewModels() private val mainActivityViewModel: MainActivityViewModel by activityViewModels() private val appProgressViewModel: AppProgressViewModel by viewModels() Loading Loading @@ -112,7 +112,7 @@ class ApplicationListFragment : Fragment(R.layout.fragment_application_list), Fu ApplicationListRVAdapter( this, privacyInfoViewModel, fdroidFetchViewModel, appInfoFetchViewModel, it, pkgManagerModule, pwaManagerModule, Loading app/src/main/java/foundation/e/apps/applicationlist/model/ApplicationListRVAdapter.kt +26 −6 Original line number Diff line number Diff line Loading @@ -34,7 +34,7 @@ import com.facebook.shimmer.Shimmer import com.facebook.shimmer.Shimmer.Direction.LEFT_TO_RIGHT import com.facebook.shimmer.ShimmerDrawable import com.google.android.material.snackbar.Snackbar import foundation.e.apps.FdroidFetchViewModel import foundation.e.apps.AppInfoFetchViewModel import foundation.e.apps.PrivacyInfoViewModel import foundation.e.apps.R import foundation.e.apps.api.cleanapk.CleanAPKInterface Loading @@ -55,7 +55,7 @@ import javax.inject.Singleton class ApplicationListRVAdapter( private val fusedAPIInterface: FusedAPIInterface, private val privacyInfoViewModel: PrivacyInfoViewModel, private val fdroidFetchViewModel: FdroidFetchViewModel, private val appInfoFetchViewModel: AppInfoFetchViewModel, private val currentDestinationId: Int, private val pkgManagerModule: PkgManagerModule, private val pwaManagerModule: PWAManagerModule, Loading Loading @@ -125,7 +125,7 @@ class ApplicationListRVAdapter( } appTitle.text = searchApp.name appAuthor.text = searchApp.author fdroidFetchViewModel.setAuthorNameIfNeeded(appAuthor, searchApp) appInfoFetchViewModel.setAuthorNameIfNeeded(appAuthor, searchApp) if (searchApp.ratings.usageQualityScore != -1.0) { appRating.text = searchApp.ratings.usageQualityScore.toString() appRatingBar.rating = searchApp.ratings.usageQualityScore.toFloat() Loading Loading @@ -200,6 +200,7 @@ class ApplicationListRVAdapter( installApplication(searchApp, appIcon) } } progressBarInstall.visibility = View.GONE } private fun ApplicationListItemBinding.handleBlocked(view: View) { Loading @@ -216,6 +217,7 @@ class ApplicationListRVAdapter( } } } progressBarInstall.visibility = View.GONE } private fun ApplicationListItemBinding.showCalculatedPrivacyScoreData( Loading Loading @@ -272,11 +274,13 @@ class ApplicationListRVAdapter( private fun ApplicationListItemBinding.handleInstalling(view: View, holder: ViewHolder) { installButton.apply { isEnabled = false text = context.getString(R.string.installing) setTextColor(context.getColor(R.color.light_grey)) backgroundTintList = ContextCompat.getColorStateList(view.context, android.R.color.transparent) strokeColor = ContextCompat.getColorStateList(view.context, R.color.light_grey) } progressBarInstall.visibility = View.GONE } private fun ApplicationListItemBinding.handleDownloading( Loading @@ -293,7 +297,9 @@ class ApplicationListRVAdapter( setOnClickListener { cancelDownload(searchApp) } progressBarInstall.visibility = View.GONE } progressBarInstall.visibility = View.GONE } private fun ApplicationListItemBinding.handleUnavailable( Loading @@ -301,14 +307,26 @@ class ApplicationListRVAdapter( searchApp: FusedApp, ) { installButton.apply { if (searchApp.isFree) { isEnabled = true text = context.getString(R.string.install) progressBarInstall.visibility = View.GONE } else { isEnabled = false text = "" progressBarInstall.visibility = View.VISIBLE appInfoFetchViewModel.isAppPurchased(searchApp).observe(lifecycleOwner) { isEnabled = true text = if (searchApp.isFree) context.getString(R.string.install) else searchApp.price progressBarInstall.visibility = View.GONE text = if (it) context.getString(R.string.install) else searchApp.price } } setTextColor(context.getColor(R.color.colorAccent)) backgroundTintList = ContextCompat.getColorStateList(view.context, android.R.color.transparent) strokeColor = ContextCompat.getColorStateList(view.context, R.color.colorAccent) setOnClickListener { if (searchApp.isFree) { if (searchApp.isFree || searchApp.isPurchased) { installApplication(searchApp, appIcon) } else { paidAppHandler?.invoke(searchApp) Loading @@ -331,6 +349,7 @@ class ApplicationListRVAdapter( installApplication(searchApp, appIcon) } } progressBarInstall.visibility = View.GONE } private fun ApplicationListItemBinding.handleInstalled( Loading @@ -351,6 +370,7 @@ class ApplicationListRVAdapter( } } } progressBarInstall.visibility = View.GONE } fun setData(newList: List<FusedApp>) { Loading Loading
app/src/main/java/foundation/e/apps/FdroidFetchViewModel.kt→app/src/main/java/foundation/e/apps/AppInfoFetchViewModel.kt +30 −2 Original line number Diff line number Diff line package foundation.e.apps import android.widget.TextView import androidx.lifecycle.LiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.liveData import androidx.lifecycle.viewModelScope import com.aurora.gplayapi.data.models.AuthData import com.google.gson.Gson import dagger.hilt.android.lifecycle.HiltViewModel import foundation.e.apps.api.fdroid.FdroidRepository import foundation.e.apps.api.fdroid.models.FdroidEntity import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.api.gplay.GPlayAPIRepository import foundation.e.apps.utils.enums.Origin import foundation.e.apps.utils.modules.DataStoreModule import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext Loading @@ -17,8 +23,11 @@ import javax.inject.Inject * */ @HiltViewModel class FdroidFetchViewModel @Inject constructor( private val fdroidRepository: FdroidRepository class AppInfoFetchViewModel @Inject constructor( private val fdroidRepository: FdroidRepository, private val gPlayAPIRepository: GPlayAPIRepository, private val dataStoreModule: DataStoreModule, private val gson: Gson ) : ViewModel() { private val fdroidEntries = mutableMapOf<String, FdroidEntity?>() Loading Loading @@ -55,4 +64,23 @@ class FdroidFetchViewModel @Inject constructor( } } } fun isAppPurchased(app: FusedApp): LiveData<Boolean> { return liveData { val authData = gson.fromJson(dataStoreModule.getAuthDataSync(), AuthData::class.java) try { gPlayAPIRepository.getDownloadInfo( app.package_name, app.latest_version_code, app.offer_type, authData ) app.isPurchased = true emit(true) } catch (e: Exception) { app.isPurchased = false emit(false) } } } }
app/src/main/java/foundation/e/apps/api/fused/data/FusedApp.kt +1 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ data class FusedApp( val url: String = String(), var type: Type = Type.NATIVE, var privacyScore: Int = -1, var isPurchased: Boolean = false, /* * List of permissions from Exodus API. Loading
app/src/main/java/foundation/e/apps/application/ApplicationFragment.kt +3 −3 Original line number Diff line number Diff line Loading @@ -44,7 +44,7 @@ import com.google.android.material.button.MaterialButton import com.google.android.material.snackbar.Snackbar import com.google.android.material.textview.MaterialTextView import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.FdroidFetchViewModel import foundation.e.apps.AppInfoFetchViewModel import foundation.e.apps.MainActivityViewModel import foundation.e.apps.PrivacyInfoViewModel import foundation.e.apps.R Loading Loading @@ -81,7 +81,7 @@ class ApplicationFragment : Fragment(R.layout.fragment_application) { private val applicationViewModel: ApplicationViewModel by viewModels() private val privacyInfoViewModel: PrivacyInfoViewModel by viewModels() private val fdroidFetchViewModel: FdroidFetchViewModel by viewModels() private val appInfoFetchViewModel: AppInfoFetchViewModel by viewModels() private val mainActivityViewModel: MainActivityViewModel by activityViewModels() private var applicationIcon: ImageView? = null Loading Loading @@ -147,7 +147,7 @@ class ApplicationFragment : Fragment(R.layout.fragment_application) { applicationIcon = appIcon appName.text = it.name appAuthor.text = it.author fdroidFetchViewModel.setAuthorNameIfNeeded(appAuthor, it) appInfoFetchViewModel.setAuthorNameIfNeeded(appAuthor, it) categoryTitle.text = it.category if (args.origin == Origin.CLEANAPK) { appIcon.load(CleanAPKInterface.ASSET_URL + it.icon_image_path) Loading
app/src/main/java/foundation/e/apps/applicationlist/ApplicationListFragment.kt +3 −3 Original line number Diff line number Diff line Loading @@ -31,8 +31,8 @@ import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.AppInfoFetchViewModel import foundation.e.apps.AppProgressViewModel import foundation.e.apps.FdroidFetchViewModel import foundation.e.apps.MainActivityViewModel import foundation.e.apps.PrivacyInfoViewModel import foundation.e.apps.R Loading Loading @@ -62,7 +62,7 @@ class ApplicationListFragment : Fragment(R.layout.fragment_application_list), Fu private val viewModel: ApplicationListViewModel by viewModels() private val privacyInfoViewModel: PrivacyInfoViewModel by viewModels() private val fdroidFetchViewModel: FdroidFetchViewModel by viewModels() private val appInfoFetchViewModel: AppInfoFetchViewModel by viewModels() private val mainActivityViewModel: MainActivityViewModel by activityViewModels() private val appProgressViewModel: AppProgressViewModel by viewModels() Loading Loading @@ -112,7 +112,7 @@ class ApplicationListFragment : Fragment(R.layout.fragment_application_list), Fu ApplicationListRVAdapter( this, privacyInfoViewModel, fdroidFetchViewModel, appInfoFetchViewModel, it, pkgManagerModule, pwaManagerModule, Loading
app/src/main/java/foundation/e/apps/applicationlist/model/ApplicationListRVAdapter.kt +26 −6 Original line number Diff line number Diff line Loading @@ -34,7 +34,7 @@ import com.facebook.shimmer.Shimmer import com.facebook.shimmer.Shimmer.Direction.LEFT_TO_RIGHT import com.facebook.shimmer.ShimmerDrawable import com.google.android.material.snackbar.Snackbar import foundation.e.apps.FdroidFetchViewModel import foundation.e.apps.AppInfoFetchViewModel import foundation.e.apps.PrivacyInfoViewModel import foundation.e.apps.R import foundation.e.apps.api.cleanapk.CleanAPKInterface Loading @@ -55,7 +55,7 @@ import javax.inject.Singleton class ApplicationListRVAdapter( private val fusedAPIInterface: FusedAPIInterface, private val privacyInfoViewModel: PrivacyInfoViewModel, private val fdroidFetchViewModel: FdroidFetchViewModel, private val appInfoFetchViewModel: AppInfoFetchViewModel, private val currentDestinationId: Int, private val pkgManagerModule: PkgManagerModule, private val pwaManagerModule: PWAManagerModule, Loading Loading @@ -125,7 +125,7 @@ class ApplicationListRVAdapter( } appTitle.text = searchApp.name appAuthor.text = searchApp.author fdroidFetchViewModel.setAuthorNameIfNeeded(appAuthor, searchApp) appInfoFetchViewModel.setAuthorNameIfNeeded(appAuthor, searchApp) if (searchApp.ratings.usageQualityScore != -1.0) { appRating.text = searchApp.ratings.usageQualityScore.toString() appRatingBar.rating = searchApp.ratings.usageQualityScore.toFloat() Loading Loading @@ -200,6 +200,7 @@ class ApplicationListRVAdapter( installApplication(searchApp, appIcon) } } progressBarInstall.visibility = View.GONE } private fun ApplicationListItemBinding.handleBlocked(view: View) { Loading @@ -216,6 +217,7 @@ class ApplicationListRVAdapter( } } } progressBarInstall.visibility = View.GONE } private fun ApplicationListItemBinding.showCalculatedPrivacyScoreData( Loading Loading @@ -272,11 +274,13 @@ class ApplicationListRVAdapter( private fun ApplicationListItemBinding.handleInstalling(view: View, holder: ViewHolder) { installButton.apply { isEnabled = false text = context.getString(R.string.installing) setTextColor(context.getColor(R.color.light_grey)) backgroundTintList = ContextCompat.getColorStateList(view.context, android.R.color.transparent) strokeColor = ContextCompat.getColorStateList(view.context, R.color.light_grey) } progressBarInstall.visibility = View.GONE } private fun ApplicationListItemBinding.handleDownloading( Loading @@ -293,7 +297,9 @@ class ApplicationListRVAdapter( setOnClickListener { cancelDownload(searchApp) } progressBarInstall.visibility = View.GONE } progressBarInstall.visibility = View.GONE } private fun ApplicationListItemBinding.handleUnavailable( Loading @@ -301,14 +307,26 @@ class ApplicationListRVAdapter( searchApp: FusedApp, ) { installButton.apply { if (searchApp.isFree) { isEnabled = true text = context.getString(R.string.install) progressBarInstall.visibility = View.GONE } else { isEnabled = false text = "" progressBarInstall.visibility = View.VISIBLE appInfoFetchViewModel.isAppPurchased(searchApp).observe(lifecycleOwner) { isEnabled = true text = if (searchApp.isFree) context.getString(R.string.install) else searchApp.price progressBarInstall.visibility = View.GONE text = if (it) context.getString(R.string.install) else searchApp.price } } setTextColor(context.getColor(R.color.colorAccent)) backgroundTintList = ContextCompat.getColorStateList(view.context, android.R.color.transparent) strokeColor = ContextCompat.getColorStateList(view.context, R.color.colorAccent) setOnClickListener { if (searchApp.isFree) { if (searchApp.isFree || searchApp.isPurchased) { installApplication(searchApp, appIcon) } else { paidAppHandler?.invoke(searchApp) Loading @@ -331,6 +349,7 @@ class ApplicationListRVAdapter( installApplication(searchApp, appIcon) } } progressBarInstall.visibility = View.GONE } private fun ApplicationListItemBinding.handleInstalled( Loading @@ -351,6 +370,7 @@ class ApplicationListRVAdapter( } } } progressBarInstall.visibility = View.GONE } fun setData(newList: List<FusedApp>) { Loading