diff --git a/app/src/main/java/com/aurora/store/data/model/MinimalApp.kt b/app/src/main/java/com/aurora/store/data/model/MinimalApp.kt index 362f3a149..28d1914c0 100644 --- a/app/src/main/java/com/aurora/store/data/model/MinimalApp.kt +++ b/app/src/main/java/com/aurora/store/data/model/MinimalApp.kt @@ -1,6 +1,9 @@ package com.aurora.store.data.model +import android.content.Context +import android.content.pm.PackageInfo import android.os.Parcelable +import androidx.core.content.pm.PackageInfoCompat import com.aurora.gplayapi.data.models.App import com.aurora.store.data.room.update.Update import kotlinx.parcelize.Parcelize @@ -21,5 +24,13 @@ data class MinimalApp( fun fromUpdate(update: Update): MinimalApp { return MinimalApp(update.packageName, update.versionCode, update.displayName) } + + fun fromPackageInfo(context: Context, packageInfo: PackageInfo): MinimalApp { + return MinimalApp( + packageInfo.packageName, + PackageInfoCompat.getLongVersionCode(packageInfo).toInt(), + packageInfo.applicationInfo!!.loadLabel(context.packageManager).toString() + ) + } } } diff --git a/app/src/main/java/com/aurora/store/util/PackageUtil.kt b/app/src/main/java/com/aurora/store/util/PackageUtil.kt index 9a6acbfdf..4a248d785 100644 --- a/app/src/main/java/com/aurora/store/util/PackageUtil.kt +++ b/app/src/main/java/com/aurora/store/util/PackageUtil.kt @@ -40,11 +40,21 @@ import com.aurora.extensions.isPAndAbove import com.aurora.extensions.isTAndAbove import com.aurora.extensions.isValidApp import com.aurora.store.BuildConfig +import java.util.Locale object PackageUtil { private const val TAG = "PackageUtil" + fun getAllValidPackages(context: Context): List { + return context.packageManager.getInstalledPackages(PackageManager.GET_META_DATA) + .filter { it.isValidApp(context.packageManager) } + .sortedBy { + it.applicationInfo!!.loadLabel(context.packageManager).toString() + .lowercase(Locale.getDefault()) + } + } + fun isInstalled(context: Context, packageName: String): Boolean { return try { getPackageInfo(context, packageName, PackageManager.GET_META_DATA) diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/PackageInfoView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/PackageInfoView.kt new file mode 100644 index 000000000..37a7cd8ba --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/PackageInfoView.kt @@ -0,0 +1,69 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views + +import android.content.Context +import android.content.pm.PackageInfo +import android.util.AttributeSet +import androidx.core.content.pm.PackageInfoCompat +import coil3.load +import coil3.request.placeholder +import coil3.request.transformations +import coil3.transform.RoundedCornersTransformation +import com.airbnb.epoxy.CallbackProp +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.store.R +import com.aurora.store.databinding.ViewPackageBinding +import com.aurora.store.util.PackageUtil + +@ModelView( + autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class PackageInfoView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp(options = [ModelProp.Option.IgnoreRequireHashCode]) + fun packageInfo(packageInfo: PackageInfo) { + val appInfo = packageInfo.applicationInfo!! + binding.imgIcon.load(PackageUtil.getIconForPackage(context, appInfo.packageName)) { + placeholder(R.drawable.bg_placeholder) + transformations(RoundedCornersTransformation(25F)) + } + + binding.txtLine1.text = appInfo.loadLabel(context.packageManager) + binding.txtLine2.text = appInfo.packageName + binding.txtLine3.text = ("${packageInfo.versionName}.${PackageInfoCompat.getLongVersionCode(packageInfo)}") + } + + @CallbackProp + fun click(onClickListener: OnClickListener?) { + binding.root.setOnClickListener(onClickListener) + } + + @CallbackProp + fun longClick(onClickListener: OnLongClickListener?) { + binding.root.setOnLongClickListener(onClickListener) + } +} diff --git a/app/src/main/java/com/aurora/store/view/ui/all/InstalledAppsFragment.kt b/app/src/main/java/com/aurora/store/view/ui/all/InstalledAppsFragment.kt index ecd71f03d..7f9bbe09c 100644 --- a/app/src/main/java/com/aurora/store/view/ui/all/InstalledAppsFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/all/InstalledAppsFragment.kt @@ -19,18 +19,18 @@ package com.aurora.store.view.ui.all +import android.content.pm.PackageInfo import android.os.Bundle import android.util.Log import android.view.View import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope -import com.aurora.gplayapi.data.models.App import com.aurora.store.AuroraApp import com.aurora.store.data.event.InstallerEvent import com.aurora.store.data.model.MinimalApp import com.aurora.store.databinding.FragmentAppsBinding import com.aurora.store.view.epoxy.views.HeaderViewModel_ -import com.aurora.store.view.epoxy.views.app.AppListViewModel_ +import com.aurora.store.view.epoxy.views.PackageInfoViewModel_ import com.aurora.store.view.epoxy.views.shimmer.AppListViewShimmerModel_ import com.aurora.store.view.ui.commons.BaseFragment import com.aurora.store.viewmodel.all.InstalledViewModel @@ -54,7 +54,7 @@ class InstalledAppsFragment : BaseFragment() { super.onViewCreated(view, savedInstanceState) viewLifecycleOwner.lifecycleScope.launch { - viewModel.installedApps.collect { + viewModel.packages.collect { updateController(it) } } @@ -75,10 +75,10 @@ class InstalledAppsFragment : BaseFragment() { } } - private fun updateController(appList: List?) { + private fun updateController(packages: List?) { binding.recycler.withModels { setFilterDuplicates(true) - if (appList == null) { + if (packages == null) { for (i in 1..10) { add( AppListViewShimmerModel_() @@ -89,16 +89,16 @@ class InstalledAppsFragment : BaseFragment() { add( HeaderViewModel_() .id("header") - .title("${appList.size} apps installed") + .title("${packages.size} apps installed") ) - appList.forEach { app -> + packages.forEach { app -> add( - AppListViewModel_() - .id(app.id) - .app(app) - .click { _ -> openDetailsFragment(app.packageName, app) } + PackageInfoViewModel_() + .id(app.packageName.hashCode()) + .packageInfo(app) + .click { _ -> openDetailsFragment(app.packageName) } .longClick { _ -> - openAppMenuSheet(MinimalApp.fromApp(app)) + openAppMenuSheet(MinimalApp.fromPackageInfo(requireContext(), app)) false } ) diff --git a/app/src/main/java/com/aurora/store/viewmodel/all/BlacklistViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/all/BlacklistViewModel.kt index 26ee0b3df..6a363afea 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/all/BlacklistViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/all/BlacklistViewModel.kt @@ -24,16 +24,14 @@ import android.content.pm.PackageInfo import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.aurora.extensions.isValidApp import com.aurora.store.data.providers.BlacklistProvider +import com.aurora.store.util.PackageUtil import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch -import kotlinx.coroutines.supervisorScope -import java.util.Locale import javax.inject.Inject @HiltViewModel @@ -55,17 +53,10 @@ class BlacklistViewModel @Inject constructor( private fun fetchApps() { viewModelScope.launch(Dispatchers.IO) { - supervisorScope { - try { - _packages.value = context.packageManager.getInstalledPackages(0) - .filter { it.isValidApp(context.packageManager) } - .sortedBy { - it.applicationInfo!!.loadLabel(context.packageManager).toString() - .lowercase(Locale.getDefault()) - } - } catch (exception: Exception) { - Log.e(TAG, "Failed to fetch apps", exception) - } + try { + _packages.value = PackageUtil.getAllValidPackages(context) + } catch (exception: Exception) { + Log.e(TAG, "Failed to fetch apps", exception) } } } diff --git a/app/src/main/java/com/aurora/store/viewmodel/all/InstalledViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/all/InstalledViewModel.kt index b816803e3..d16ddfa01 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/all/InstalledViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/all/InstalledViewModel.kt @@ -20,12 +20,10 @@ package com.aurora.store.viewmodel.all import android.content.Context +import android.content.pm.PackageInfo import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.aurora.gplayapi.data.models.App -import com.aurora.gplayapi.helpers.AppDetailsHelper -import com.aurora.store.data.providers.BlacklistProvider import com.aurora.store.util.PackageUtil import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.qualifiers.ApplicationContext @@ -33,20 +31,17 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch -import java.util.Locale import javax.inject.Inject @HiltViewModel class InstalledViewModel @Inject constructor( - private val appDetailsHelper: AppDetailsHelper, - private val blacklistProvider: BlacklistProvider, @ApplicationContext private val context: Context ) : ViewModel() { private val TAG = InstalledViewModel::class.java.simpleName - private val _installedApps = MutableStateFlow?>(null) - val installedApps = _installedApps.asStateFlow() + private val _packages = MutableStateFlow?>(null) + val packages = _packages.asStateFlow() init { fetchApps() @@ -55,16 +50,9 @@ class InstalledViewModel @Inject constructor( fun fetchApps() { viewModelScope.launch(Dispatchers.IO) { try { - PackageUtil.getPackageInfoMap(context).keys.let { packages -> - val filtersPackages = packages.filter { !blacklistProvider.isBlacklisted(it) } - - _installedApps.value = appDetailsHelper.getAppByPackageName(filtersPackages) - .filter { it.displayName.isNotEmpty() } - .map { it.isInstalled = true; it } - .sortedBy { it.displayName.lowercase(Locale.getDefault()) } - } + _packages.value = PackageUtil.getAllValidPackages(context) } catch (exception: Exception) { - Log.e(TAG, "Failed to get installed apps", exception) + Log.e(TAG, "Failed to fetch apps", exception) } } } diff --git a/app/src/main/res/layout/view_package.xml b/app/src/main/res/layout/view_package.xml new file mode 100644 index 000000000..cfc884982 --- /dev/null +++ b/app/src/main/res/layout/view_package.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + +