InstalledAppsFragment: Show all installed packages similar to blacklist
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<PackageInfo> {
|
||||
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)
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
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<ViewPackageBinding>(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)
|
||||
}
|
||||
}
|
||||
@@ -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<FragmentAppsBinding>() {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewModel.installedApps.collect {
|
||||
viewModel.packages.collect {
|
||||
updateController(it)
|
||||
}
|
||||
}
|
||||
@@ -75,10 +75,10 @@ class InstalledAppsFragment : BaseFragment<FragmentAppsBinding>() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateController(appList: List<App>?) {
|
||||
private fun updateController(packages: List<PackageInfo>?) {
|
||||
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<FragmentAppsBinding>() {
|
||||
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
|
||||
}
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<List<App>?>(null)
|
||||
val installedApps = _installedApps.asStateFlow()
|
||||
private val _packages = MutableStateFlow<List<PackageInfo>?>(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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
63
app/src/main/res/layout/view_package.xml
Normal file
63
app/src/main/res/layout/view_package.xml
Normal file
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Aurora Store
|
||||
~ Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
~
|
||||
~ 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 <http://www.gnu.org/licenses/>.
|
||||
~
|
||||
-->
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="@dimen/padding_normal"
|
||||
android:paddingTop="@dimen/padding_xsmall"
|
||||
android:paddingEnd="@dimen/padding_small"
|
||||
android:paddingBottom="@dimen/padding_xsmall">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/img_icon"
|
||||
android:layout_width="@dimen/icon_size_medium"
|
||||
android:layout_height="@dimen/icon_size_medium"
|
||||
android:layout_centerVertical="true" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/txt_line1"
|
||||
style="@style/AuroraTextStyle.Line1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/margin_normal"
|
||||
android:layout_toEndOf="@id/img_icon" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/txt_line2"
|
||||
style="@style/AuroraTextStyle.Line2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/txt_line1"
|
||||
android:layout_alignStart="@id/txt_line1"
|
||||
android:layout_alignEnd="@id/txt_line1"
|
||||
android:layout_marginTop="@dimen/margin_xxsmall" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/txt_line3"
|
||||
style="@style/AuroraTextStyle.Line3"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/txt_line2"
|
||||
android:layout_alignStart="@id/txt_line1"
|
||||
android:layout_alignEnd="@id/txt_line1"
|
||||
android:layout_marginTop="@dimen/margin_xxsmall" />
|
||||
</RelativeLayout>
|
||||
Reference in New Issue
Block a user