mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-23 11:05:59 +00:00
Fix Managed configurations bugs, add search bar (#198)
This commit is contained in:
@@ -602,7 +602,7 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) {
|
|||||||
}
|
}
|
||||||
composable<ManagedConfiguration> {
|
composable<ManagedConfiguration> {
|
||||||
ManagedConfigurationScreen(
|
ManagedConfigurationScreen(
|
||||||
it.toRoute(), vm.appRestrictions, vm::getAppRestrictions, vm::setAppRestrictions,
|
it.toRoute(), vm.appRestrictions, vm::setAppRestrictions,
|
||||||
vm::clearAppRestrictions, ::navigateUp
|
vm::clearAppRestrictions, ::navigateUp
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -518,12 +518,11 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
|
|||||||
|
|
||||||
@RequiresApi(23)
|
@RequiresApi(23)
|
||||||
fun getAppRestrictions(name: String) {
|
fun getAppRestrictions(name: String) {
|
||||||
val rm = application.getSystemService(Context.RESTRICTIONS_SERVICE) as RestrictionsManager
|
val rm = application.getSystemService(RestrictionsManager::class.java)
|
||||||
val bundle = DPM.getApplicationRestrictions(DAR, name)
|
val bundle = DPM.getApplicationRestrictions(DAR, name)
|
||||||
println(bundle.keySet())
|
appRestrictions.value = rm.getManifestRestrictions(name)?.mapNotNull {
|
||||||
appRestrictions.value = rm.getManifestRestrictions(name).mapNotNull {
|
|
||||||
transformRestrictionEntry(it)
|
transformRestrictionEntry(it)
|
||||||
}.map {
|
}?.map {
|
||||||
if (bundle.containsKey(it.key)) {
|
if (bundle.containsKey(it.key)) {
|
||||||
when (it) {
|
when (it) {
|
||||||
is AppRestriction.BooleanItem -> it.value = bundle.getBoolean(it.key)
|
is AppRestriction.BooleanItem -> it.value = bundle.getBoolean(it.key)
|
||||||
@@ -534,17 +533,16 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
it
|
it
|
||||||
}
|
} ?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(23)
|
@RequiresApi(23)
|
||||||
fun setAppRestrictions(name: String, item: AppRestriction) {
|
fun setAppRestrictions(name: String, item: AppRestriction) {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
appRestrictions.value = emptyList()
|
val bundle = transformAppRestriction(
|
||||||
DPM.setApplicationRestrictions(
|
appRestrictions.value.filter { it.key != item.key }.plus(item)
|
||||||
DAR, name,
|
|
||||||
transformAppRestriction(appRestrictions.value.filter { it.key != item.key }.plus(item))
|
|
||||||
)
|
)
|
||||||
|
DPM.setApplicationRestrictions(DAR, name, bundle)
|
||||||
getAppRestrictions(name)
|
getAppRestrictions(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import androidx.compose.foundation.text.KeyboardOptions
|
|||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.automirrored.filled.List
|
import androidx.compose.material.icons.automirrored.filled.List
|
||||||
|
import androidx.compose.material.icons.outlined.Clear
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
@@ -122,15 +123,12 @@ fun AppChooserScreen(
|
|||||||
keyboardActions = KeyboardActions { focusMgr.clearFocus() },
|
keyboardActions = KeyboardActions { focusMgr.clearFocus() },
|
||||||
placeholder = { Text(stringResource(R.string.search)) },
|
placeholder = { Text(stringResource(R.string.search)) },
|
||||||
trailingIcon = {
|
trailingIcon = {
|
||||||
Icon(
|
IconButton({
|
||||||
painter = painterResource(R.drawable.close_fill0),
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier.clickable {
|
|
||||||
focusMgr.clearFocus()
|
|
||||||
query = ""
|
query = ""
|
||||||
searchMode = false
|
searchMode = false
|
||||||
|
}) {
|
||||||
|
Icon(Icons.Outlined.Clear, null)
|
||||||
}
|
}
|
||||||
)
|
|
||||||
},
|
},
|
||||||
textStyle = typography.bodyLarge,
|
textStyle = typography.bodyLarge,
|
||||||
modifier = Modifier.fillMaxWidth().focusRequester(fr)
|
modifier = Modifier.fillMaxWidth().focusRequester(fr)
|
||||||
|
|||||||
@@ -40,7 +40,9 @@ import androidx.compose.material.icons.filled.Check
|
|||||||
import androidx.compose.material.icons.filled.Clear
|
import androidx.compose.material.icons.filled.Clear
|
||||||
import androidx.compose.material.icons.filled.MoreVert
|
import androidx.compose.material.icons.filled.MoreVert
|
||||||
import androidx.compose.material.icons.outlined.CheckCircle
|
import androidx.compose.material.icons.outlined.CheckCircle
|
||||||
|
import androidx.compose.material.icons.outlined.Clear
|
||||||
import androidx.compose.material.icons.outlined.Delete
|
import androidx.compose.material.icons.outlined.Delete
|
||||||
|
import androidx.compose.material.icons.outlined.Search
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.AlertDialogDefaults
|
import androidx.compose.material3.AlertDialogDefaults
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
@@ -79,6 +81,8 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
@@ -258,7 +262,11 @@ fun ApplicationDetailsScreen(
|
|||||||
var dialog by rememberSaveable { mutableIntStateOf(0) } // 1: clear storage, 2: uninstall
|
var dialog by rememberSaveable { mutableIntStateOf(0) } // 1: clear storage, 2: uninstall
|
||||||
val info = vm.getAppInfo(packageName)
|
val info = vm.getAppInfo(packageName)
|
||||||
val status by vm.appStatus.collectAsStateWithLifecycle()
|
val status by vm.appStatus.collectAsStateWithLifecycle()
|
||||||
LaunchedEffect(Unit) { vm.getAppStatus(packageName) }
|
val appRestrictions by vm.appRestrictions.collectAsStateWithLifecycle()
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
vm.getAppStatus(packageName)
|
||||||
|
vm.getAppRestrictions(packageName)
|
||||||
|
}
|
||||||
MySmallTitleScaffold(R.string.place_holder, onNavigateUp, 0.dp) {
|
MySmallTitleScaffold(R.string.place_holder, onNavigateUp, 0.dp) {
|
||||||
Column(Modifier.align(Alignment.CenterHorizontally).padding(top = 16.dp), horizontalAlignment = Alignment.CenterHorizontally) {
|
Column(Modifier.align(Alignment.CenterHorizontally).padding(top = 16.dp), horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
Image(rememberDrawablePainter(info.icon), null, Modifier.size(50.dp))
|
Image(rememberDrawablePainter(info.icon), null, Modifier.size(50.dp))
|
||||||
@@ -295,7 +303,7 @@ fun ApplicationDetailsScreen(
|
|||||||
state = status.keepUninstalled,
|
state = status.keepUninstalled,
|
||||||
onCheckedChange = { vm.adSetPackageKu(packageName, it) }
|
onCheckedChange = { vm.adSetPackageKu(packageName, it) }
|
||||||
)
|
)
|
||||||
if (VERSION.SDK_INT >= 23) {
|
if (VERSION.SDK_INT >= 23 && appRestrictions.isNotEmpty()) {
|
||||||
FunctionItem(R.string.managed_configuration, icon = R.drawable.description_fill0) {
|
FunctionItem(R.string.managed_configuration, icon = R.drawable.description_fill0) {
|
||||||
onNavigate(ManagedConfiguration(packageName))
|
onNavigate(ManagedConfiguration(packageName))
|
||||||
}
|
}
|
||||||
@@ -1003,35 +1011,74 @@ fun EditAppGroupScreen(
|
|||||||
@Composable
|
@Composable
|
||||||
fun ManagedConfigurationScreen(
|
fun ManagedConfigurationScreen(
|
||||||
params: ManagedConfiguration, appRestrictions: StateFlow<List<AppRestriction>>,
|
params: ManagedConfiguration, appRestrictions: StateFlow<List<AppRestriction>>,
|
||||||
getRestriction: (String) -> Unit, setRestriction: (String, AppRestriction) -> Unit,
|
setRestriction: (String, AppRestriction) -> Unit, clearRestriction: (String) -> Unit,
|
||||||
clearRestriction: (String) -> Unit, navigateUp: () -> Unit
|
navigateUp: () -> Unit
|
||||||
) {
|
) {
|
||||||
val restrictions by appRestrictions.collectAsStateWithLifecycle()
|
val restrictions by appRestrictions.collectAsStateWithLifecycle()
|
||||||
var dialog by remember { mutableIntStateOf(-1) }
|
var searchMode by remember { mutableStateOf(false) }
|
||||||
var clearRestrictionDialog by remember { mutableStateOf(false) }
|
var searchKeyword by remember { mutableStateOf("") }
|
||||||
LaunchedEffect(Unit) {
|
val displayRestrictions = if (searchKeyword.isEmpty()) {
|
||||||
getRestriction(params.packageName)
|
restrictions
|
||||||
|
} else {
|
||||||
|
restrictions.filter {
|
||||||
|
it.key.contentEquals(searchKeyword, true) ||
|
||||||
|
it.title?.contains(searchKeyword, true) ?: true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
var dialog by remember { mutableStateOf<AppRestriction?>(null) }
|
||||||
|
var clearRestrictionDialog by remember { mutableStateOf(false) }
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
{ Text(stringResource(R.string.managed_configuration)) },
|
{
|
||||||
|
if (searchMode) {
|
||||||
|
val fr = remember { FocusRequester() }
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
fr.requestFocus()
|
||||||
|
}
|
||||||
|
OutlinedTextField(
|
||||||
|
searchKeyword, { searchKeyword = it },
|
||||||
|
Modifier.fillMaxWidth().focusRequester(fr),
|
||||||
|
textStyle = typography.bodyLarge,
|
||||||
|
placeholder = { Text(stringResource(R.string.search)) },
|
||||||
|
trailingIcon = {
|
||||||
|
IconButton({
|
||||||
|
searchKeyword = ""
|
||||||
|
searchMode = false
|
||||||
|
}) {
|
||||||
|
Icon(Icons.Outlined.Clear, null)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Text(stringResource(R.string.managed_configuration))
|
||||||
|
}
|
||||||
|
},
|
||||||
navigationIcon = { NavIcon(navigateUp) },
|
navigationIcon = { NavIcon(navigateUp) },
|
||||||
actions = {
|
actions = {
|
||||||
|
if (!searchMode) {
|
||||||
|
IconButton({
|
||||||
|
searchMode = true
|
||||||
|
}) {
|
||||||
|
Icon(Icons.Outlined.Search, null)
|
||||||
|
}
|
||||||
IconButton({
|
IconButton({
|
||||||
clearRestrictionDialog = true
|
clearRestrictionDialog = true
|
||||||
}) {
|
}) {
|
||||||
Icon(Icons.Outlined.Delete, null)
|
Icon(Icons.Outlined.Delete, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
contentWindowInsets = adaptiveInsets()
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
LazyColumn(Modifier.padding(paddingValues)) {
|
LazyColumn(Modifier.padding(paddingValues)) {
|
||||||
itemsIndexed(restrictions) { index, entry ->
|
items(displayRestrictions, { it.key }) { entry ->
|
||||||
Row(
|
Row(
|
||||||
Modifier.fillMaxWidth().clickable {
|
Modifier.fillMaxWidth().clickable {
|
||||||
dialog = index
|
dialog = entry
|
||||||
}.padding(HorizontalPadding, 8.dp),
|
}.padding(HorizontalPadding, 8.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
@@ -1055,7 +1102,13 @@ fun ManagedConfigurationScreen(
|
|||||||
is AppRestriction.StringItem -> entry.value?.take(30)
|
is AppRestriction.StringItem -> entry.value?.take(30)
|
||||||
is AppRestriction.BooleanItem -> entry.value?.toString()
|
is AppRestriction.BooleanItem -> entry.value?.toString()
|
||||||
is AppRestriction.ChoiceItem -> entry.value
|
is AppRestriction.ChoiceItem -> entry.value
|
||||||
is AppRestriction.MultiSelectItem -> entry.value?.joinToString(limit = 30)
|
is AppRestriction.MultiSelectItem -> {
|
||||||
|
if (entry.value != null) {
|
||||||
|
entry.entryValues
|
||||||
|
.filter { entry.value?.contains(it) ?: false }
|
||||||
|
.joinToString(limit = 30)
|
||||||
|
} else null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Text(
|
Text(
|
||||||
text ?: "null", Modifier.alpha(0.7F),
|
text ?: "null", Modifier.alpha(0.7F),
|
||||||
@@ -1070,8 +1123,8 @@ fun ManagedConfigurationScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dialog != -1) Dialog({
|
if (dialog != null) Dialog({
|
||||||
dialog = -1
|
dialog = null
|
||||||
}) {
|
}) {
|
||||||
Surface(
|
Surface(
|
||||||
color = AlertDialogDefaults.containerColor,
|
color = AlertDialogDefaults.containerColor,
|
||||||
@@ -1079,11 +1132,11 @@ fun ManagedConfigurationScreen(
|
|||||||
tonalElevation = AlertDialogDefaults.TonalElevation,
|
tonalElevation = AlertDialogDefaults.TonalElevation,
|
||||||
) {
|
) {
|
||||||
Column(Modifier.verticalScroll(rememberScrollState()).padding(12.dp)) {
|
Column(Modifier.verticalScroll(rememberScrollState()).padding(12.dp)) {
|
||||||
ManagedConfigurationDialog(restrictions[dialog]) {
|
ManagedConfigurationDialog(dialog!!) {
|
||||||
if (it != null) {
|
if (it != null) {
|
||||||
setRestriction(params.packageName, it)
|
setRestriction(params.packageName, it)
|
||||||
}
|
}
|
||||||
dialog = -1
|
dialog = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user