ViewModel refactoring: Settings part

User restriction shortcuts
Optimize ShortcutUtils
Fix Private DNS bug
This commit is contained in:
BinTianqi
2025-10-12 13:16:50 +08:00
parent 44aad18814
commit 9e1d18b8e7
22 changed files with 420 additions and 266 deletions

View File

@@ -443,13 +443,13 @@ fun handlePrivilegeChange(context: Context) {
SP.dhizukuServer = false
SP.shortcuts = privilege.activated
if (privilege.activated) {
ShortcutUtils.setAllShortcuts(context)
ShortcutUtils.setAllShortcuts(context, true)
if (!privilege.dhizuku) {
setDefaultAffiliationID()
}
} else {
SP.isDefaultAffiliationIdSet = false
ShortcutUtils.setAllShortcuts(context)
SP.isApiEnabled = false
ShortcutUtils.setAllShortcuts(context, false)
SP.apiKeyHash = ""
}
}

View File

@@ -70,7 +70,6 @@ import androidx.compose.material3.FilledTonalIconButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MenuAnchorType
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
@@ -115,7 +114,7 @@ import com.bintianqi.owndroid.MyViewModel
import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.formatFileSize
import com.bintianqi.owndroid.formatTime
import com.bintianqi.owndroid.formatDate
import com.bintianqi.owndroid.popToast
import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.ErrorDialog
@@ -511,7 +510,7 @@ fun UpdateNetworkScreen(info: WifiInfo, setNetwork: (WifiInfo) -> Boolean, onNav
TopAppBar(
{ Text(stringResource(R.string.update_network)) },
navigationIcon = { NavIcon(onNavigateUp) },
colors = TopAppBarDefaults.topAppBarColors(colorScheme.surfaceContainer)
colors = TopAppBarDefaults.topAppBarColors(MaterialTheme.colorScheme.surfaceContainer)
)
},
contentWindowInsets = WindowInsets.ime
@@ -1046,14 +1045,14 @@ fun NetworkStatsScreen(
}
}
OutlinedTextField(
value = startTime.let { if(it == -1L) "" else formatTime(it) }, onValueChange = {}, readOnly = true,
value = startTime.let { if(it == -1L) "" else formatDate(it) }, onValueChange = {}, readOnly = true,
label = { Text(stringResource(R.string.start_time)) },
interactionSource = startTimeIs,
isError = startTime >= endTime,
modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp)
)
OutlinedTextField(
value = formatTime(endTime), onValueChange = {}, readOnly = true,
value = formatDate(endTime), onValueChange = {}, readOnly = true,
label = { Text(stringResource(R.string.end_time)) },
interactionSource = endTimeIs,
isError = startTime >= endTime,
@@ -1292,7 +1291,7 @@ fun NetworkStatsViewerScreen(
HorizontalPager(ps, Modifier.padding(top = 8.dp)) { page ->
val item = data[index]
Column(Modifier.fillMaxWidth().padding(horizontal = HorizontalPadding)) {
Text(formatTime(item.startTime) + "\n~\n" + formatTime(item.endTime),
Text(formatDate(item.startTime) + "\n~\n" + formatDate(item.endTime),
Modifier.align(Alignment.CenterHorizontally), textAlign = TextAlign.Center)
Spacer(Modifier.height(5.dp))
val txBytes = item.txBytes
@@ -1350,7 +1349,7 @@ enum class PrivateDnsMode(val id: Int, val text: Int) {
Host(DevicePolicyManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, R.string.enabled)
}
data class PrivateDnsConfiguration(val mode: PrivateDnsMode, val host: String)
data class PrivateDnsConfiguration(val mode: PrivateDnsMode?, val host: String)
@Serializable object PrivateDns
@@ -1362,7 +1361,7 @@ fun PrivateDnsScreen(
) {
val context = LocalContext.current
val focusMgr = LocalFocusManager.current
var mode by remember { mutableStateOf(PrivateDnsMode.Opportunistic) }
var mode by remember { mutableStateOf<PrivateDnsMode?>(PrivateDnsMode.Opportunistic) }
var inputHost by remember { mutableStateOf("") }
LaunchedEffect(Unit) {
val conf = getPrivateDns()
@@ -1385,7 +1384,8 @@ fun PrivateDnsScreen(
val result = setPrivateDns(PrivateDnsConfiguration(mode, inputHost))
context.showOperationResultToast(result)
},
modifier = Modifier.fillMaxWidth().padding(horizontal = HorizontalPadding)
modifier = Modifier.fillMaxWidth().padding(horizontal = HorizontalPadding),
enabled = mode != null
) {
Text(stringResource(R.string.apply))
}

View File

@@ -30,6 +30,8 @@ import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.OutlinedTextField
@@ -45,6 +47,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
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.text.input.KeyboardType
@@ -56,6 +59,7 @@ import com.bintianqi.owndroid.MyViewModel
import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.SP
import com.bintianqi.owndroid.generateBase64Key
import com.bintianqi.owndroid.popToast
import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.CheckBoxItem
@@ -250,7 +254,12 @@ fun ResetPasswordTokenScreen(
OutlinedTextField(
token, { token = it }, Modifier.fillMaxWidth(),
label = { Text(stringResource(R.string.token)) },
supportingText = { Text("${token.length}/32") }
supportingText = { Text("${token.length}/32") },
trailingIcon = {
IconButton({ token = generateBase64Key(24) }) {
Icon(painterResource(R.drawable.casino_fill0), null)
}
}
)
Button(
onClick = {
@@ -265,7 +274,12 @@ fun ResetPasswordTokenScreen(
}
if (state.set && !state.active) Button(
onClick = {
getIntent()?.let { launcher.launch(it) }
val intent = getIntent()
if (intent == null) {
context.showOperationResultToast(false)
} else {
launcher.launch(intent)
}
},
modifier = Modifier.fillMaxWidth()
) {

View File

@@ -112,7 +112,7 @@ import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.SP
import com.bintianqi.owndroid.formatFileSize
import com.bintianqi.owndroid.formatTime
import com.bintianqi.owndroid.formatDate
import com.bintianqi.owndroid.popToast
import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.CheckBoxItem
@@ -588,7 +588,7 @@ fun ChangeTimeScreen(setTime: (Long, Boolean) -> Boolean, onNavigateUp: () -> Un
) {
if(page == 0) {
OutlinedTextField(
value = datePickerState.selectedDateMillis?.let { formatTime(it) } ?: "",
value = datePickerState.selectedDateMillis?.let { formatDate(it) } ?: "",
onValueChange = {}, readOnly = true,
label = { Text(stringResource(R.string.date)) },
interactionSource = dateInteractionSource,
@@ -1436,9 +1436,9 @@ fun CaCertScreen(
Text("Issuer", style = typography.labelLarge)
SelectionContainer { Text(cert.issuer) }
Text("Issued on", style = typography.labelLarge)
SelectionContainer { Text(formatTime(cert.issuedTime)) }
SelectionContainer { Text(formatDate(cert.issuedTime)) }
Text("Expires on", style = typography.labelLarge)
SelectionContainer { Text(formatTime(cert.expiresTime)) }
SelectionContainer { Text(formatDate(cert.expiresTime)) }
Text("SHA-256 fingerprint", style = typography.labelLarge)
SelectionContainer { Text(cert.hash) }
if (dialog == 2) Row(
@@ -1929,7 +1929,7 @@ fun SystemUpdatePolicyScreen(
if (VERSION.SDK_INT >= 26) {
Column(Modifier.padding(HorizontalPadding)) {
if (pendingUpdate.exists) {
Text(stringResource(R.string.update_received_time, formatTime(pendingUpdate.time)))
Text(stringResource(R.string.update_received_time, formatDate(pendingUpdate.time)))
Text(stringResource(R.string.is_security_patch,
stringResource(pendingUpdate.securityPatch.yesOrNo)))
} else {

View File

@@ -1,6 +1,8 @@
package com.bintianqi.owndroid.dpm
import androidx.annotation.RequiresApi
import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -14,6 +16,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
@@ -21,6 +24,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
@@ -54,6 +58,7 @@ import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.UserRestrictionCategory
import com.bintianqi.owndroid.UserRestrictionsRepository
import com.bintianqi.owndroid.popToast
import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.FunctionItem
import com.bintianqi.owndroid.ui.MyLazyScaffold
@@ -117,6 +122,17 @@ fun UserRestrictionScreen(
onNavigate(UserRestrictionOptions(it.name))
}
}
Row(
Modifier
.padding(HorizontalPadding, 10.dp)
.fillMaxWidth()
.background(colorScheme.primaryContainer, RoundedCornerShape(8.dp))
.padding(8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(Icons.Outlined.Info, null, Modifier.padding(end = 8.dp), colorScheme.onPrimaryContainer)
Text(stringResource(R.string.user_restriction_tip), color = colorScheme.onPrimaryContainer)
}
}
}
}
@@ -128,7 +144,8 @@ data class UserRestrictionOptions(val id: String)
@Composable
fun UserRestrictionOptionsScreen(
args: UserRestrictionOptions, userRestrictions: StateFlow<Map<String, Boolean>>,
setRestriction: (String, Boolean) -> Boolean, onNavigateUp: () -> Unit
setRestriction: (String, Boolean) -> Boolean, setShortcut: (String) -> Boolean,
onNavigateUp: () -> Unit
) {
val context = LocalContext.current
val status by userRestrictions.collectAsStateWithLifecycle()
@@ -136,7 +153,12 @@ fun UserRestrictionOptionsScreen(
MyLazyScaffold(title, onNavigateUp) {
items(items) { restriction ->
Row(
Modifier.fillMaxWidth().padding(15.dp, 6.dp),
Modifier
.fillMaxWidth()
.combinedClickable(onClick = {}, onLongClick = {
if (!setShortcut(restriction.id)) context.popToast(R.string.unsupported)
})
.padding(15.dp, 6.dp),
Arrangement.SpaceBetween, Alignment.CenterVertically
) {
Row(Modifier.weight(1F), verticalAlignment = Alignment.CenterVertically) {

View File

@@ -58,7 +58,7 @@ import com.bintianqi.owndroid.HorizontalPadding
import com.bintianqi.owndroid.MyViewModel
import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.formatTime
import com.bintianqi.owndroid.formatDate
import com.bintianqi.owndroid.popToast
import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.CircularProgressDialog
@@ -205,7 +205,7 @@ fun UserInfoScreen(getInfo: () -> UserInformation, onNavigateUp: () -> Unit) {
if (VERSION.SDK_INT >= 23) InfoItem(R.string.system_user, info.system.yesOrNo)
if (VERSION.SDK_INT >= 34) InfoItem(R.string.admin_user, info.admin.yesOrNo)
if (VERSION.SDK_INT >= 25) InfoItem(R.string.demo_user, info.demo.yesOrNo)
if (info.time != 0L) InfoItem(R.string.creation_time, formatTime(info.time))
if (info.time != 0L) InfoItem(R.string.creation_time, formatDate(info.time))
if (VERSION.SDK_INT >= 28) {
InfoItem(R.string.logout_enabled, info.logout.yesOrNo)