search in Package selector

optimize system app filter in Package selector
fix UserRestrictionItem padding
This commit is contained in:
BinTianqi
2024-08-05 18:00:58 +08:00
parent 7b4fccd54b
commit b908a50686
6 changed files with 103 additions and 72 deletions

View File

@@ -1,28 +1,52 @@
package com.bintianqi.owndroid
import android.content.pm.ApplicationInfo
import android.graphics.drawable.Drawable
import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.runtime.*
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import com.bintianqi.owndroid.ui.NavIcon
@@ -36,12 +60,12 @@ private data class PkgInfo(
val pkgName: String,
val label: String,
val icon: Drawable,
val type:String
val system: Boolean
)
private val pkgs = mutableListOf<PkgInfo>()
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PackageSelector(navCtrl: NavHostController, pkgName: MutableState<String>) {
val context = LocalContext.current
@@ -50,8 +74,10 @@ fun PackageSelector(navCtrl: NavHostController, pkgName: MutableState<String>) {
var progress by remember { mutableIntStateOf(0) }
var show by remember { mutableStateOf(true) }
var hideProgress by remember { mutableStateOf(true) }
var filter by remember { mutableStateOf("data") }
var system by remember { mutableStateOf(false) }
var search by remember { mutableStateOf("") }
val scrollState = rememberLazyListState()
val focusMgr = LocalFocusManager.current
val co = rememberCoroutineScope()
val getPkgList: suspend ()->Unit = {
show = false
@@ -59,16 +85,9 @@ fun PackageSelector(navCtrl: NavHostController, pkgName: MutableState<String>) {
hideProgress = false
pkgs.clear()
for(pkg in apps) {
val srcDir = pkg.sourceDir
pkgs += PkgInfo(
pkg.packageName, pkg.loadLabel(pm).toString(), pkg.loadIcon(pm),
if(srcDir.contains("/data/")) { "data" }
else if(
srcDir.contains("system/priv-app")||srcDir.contains("product/priv-app")||
srcDir.contains("ext/priv-app")||srcDir.contains("vendor/priv-app")
) {"priv"}
else if(srcDir.contains("apex")) {"apex"}
else{"system"}
(pkg.flags and ApplicationInfo.FLAG_SYSTEM) != 0
)
withContext(Dispatchers.Main) { progress += 1 }
}
@@ -84,50 +103,47 @@ fun PackageSelector(navCtrl: NavHostController, pkgName: MutableState<String>) {
painter = painterResource(R.drawable.filter_alt_fill0),
contentDescription = "filter",
modifier = Modifier
.padding(horizontal = 6.dp)
.padding(horizontal = 4.dp)
.clip(RoundedCornerShape(50))
.combinedClickable(
onClick = {
when(filter) {
"data"-> {
filter = "system"; co.launch {scrollState.scrollToItem(0) }
Toast.makeText(context, R.string.show_system_app, Toast.LENGTH_SHORT).show()
}
"system"-> {
filter = "priv"; co.launch {scrollState.scrollToItem(0) }
Toast.makeText(context, R.string.show_priv_app, Toast.LENGTH_SHORT).show()
}
else-> {
filter = "data"; co.launch {scrollState.scrollToItem(0) }
Toast.makeText(context, R.string.show_user_app, Toast.LENGTH_SHORT).show()
}
}
},
onLongClick = {
filter = "apex"
Toast.makeText(context, R.string.show_apex_app, Toast.LENGTH_SHORT).show()
}
)
.clickable {
system = !system
Toast.makeText(context, if(system) R.string.show_system_app else R.string.show_user_app, Toast.LENGTH_SHORT).show()
}
.padding(5.dp)
)
Icon(
painter = painterResource(R.drawable.refresh_fill0),
contentDescription = "refresh",
modifier = Modifier
.padding(horizontal = 6.dp)
.padding(horizontal = 4.dp)
.clip(RoundedCornerShape(50))
.clickable{
co.launch{
getPkgList()
}
.clickable {
co.launch { getPkgList() }
}
.padding(5.dp)
)
},
title = {
Text(text = stringResource(R.string.pkg_selector))
OutlinedTextField(
value = search,
onValueChange = { search = it },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
keyboardActions = KeyboardActions { focusMgr.clearFocus() },
placeholder = { Text(stringResource(R.string.search)) },
trailingIcon = {
Icon(
painter = painterResource(R.drawable.close_fill0),
contentDescription = "clear search",
modifier = Modifier.clickable {
search = ""
focusMgr.clearFocus()
}
)
},
modifier = Modifier.padding(vertical = 8.dp)
)
},
navigationIcon = { NavIcon{navCtrl.navigateUp() } },
navigationIcon = { NavIcon{ navCtrl.navigateUp() } },
colors = TopAppBarDefaults.topAppBarColors(containerColor = colorScheme.background)
)
}
@@ -144,12 +160,18 @@ fun PackageSelector(navCtrl: NavHostController, pkgName: MutableState<String>) {
}
if(show) {
items(pkgs) {
if(filter == it.type) {
PackageItem(it, navCtrl, pkgName)
if(system == it.system) {
if(search != "") {
if(it.pkgName.contains(search, ignoreCase = true) || it.label.contains(search, ignoreCase = true)) {
PackageItem(it, navCtrl, pkgName)
}
} else {
PackageItem(it, navCtrl, pkgName)
}
}
}
items(1) { Spacer(Modifier.padding(vertical = 30.dp)) }
}else{
} else {
items(1) {
Spacer(Modifier.padding(top = 5.dp))
Text(text = stringResource(R.string.loading), modifier = Modifier.alpha(0.8F))
@@ -157,7 +179,7 @@ fun PackageSelector(navCtrl: NavHostController, pkgName: MutableState<String>) {
}
}
LaunchedEffect(Unit) {
if(pkgs.size==0) { getPkgList() }
if(pkgs.size == 0) { getPkgList() }
}
}
}

View File

@@ -8,6 +8,7 @@ import android.widget.Toast
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
@@ -192,24 +193,25 @@ private fun UserRestrictionItem(
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
SwitchItem(
itemName,restrictionDescription,leadIcon,
{ if(context.isDeviceOwner||context.isProfileOwner) { dpm.getUserRestrictions(receiver).getBoolean(restriction) }else{ false } },
{
try{
if(it) {
dpm.addUserRestriction(receiver,restriction)
}else{
dpm.clearUserRestriction(receiver,restriction)
}
}catch(e:SecurityException) {
if(context.isProfileOwner) {
Toast.makeText(context, R.string.require_device_owner, Toast.LENGTH_SHORT).show()
Box(modifier = Modifier.padding(start = 22.dp, end = 16.dp)) {
SwitchItem(
itemName,restrictionDescription,leadIcon,
{ if(context.isDeviceOwner||context.isProfileOwner) { dpm.getUserRestrictions(receiver).getBoolean(restriction) }else{ false } },
{
try{
if(it) {
dpm.addUserRestriction(receiver,restriction)
}else{
dpm.clearUserRestriction(receiver,restriction)
}
}catch(e:SecurityException) {
if(context.isProfileOwner) {
Toast.makeText(context, R.string.require_device_owner, Toast.LENGTH_SHORT).show()
}
}
}
},
context.isDeviceOwner||context.isProfileOwner
)
)
}
}
object RestrictionData {