Optimize UI

Change version to v6.5(37)
This commit is contained in:
BinTianqi
2025-03-01 13:16:21 +08:00
parent 1de95e336b
commit 02c76ea436
16 changed files with 195 additions and 210 deletions

View File

@@ -24,8 +24,8 @@ android {
applicationId = "com.bintianqi.owndroid"
minSdk = 21
targetSdk = 35
versionCode = 36
versionName = "6.4"
versionCode = 37
versionName = "6.5"
multiDexEnabled = false
}

View File

@@ -35,7 +35,7 @@ import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import androidx.core.content.edit
import com.bintianqi.owndroid.ui.FunctionItem
import com.bintianqi.owndroid.ui.InfoCard
import com.bintianqi.owndroid.ui.Notes
import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.SwitchItem
import kotlinx.serialization.Serializable
@@ -214,7 +214,7 @@ fun ApiSettings(onNavigateUp: () -> Unit) {
) {
Text(stringResource(R.string.apply))
}
if(sp.apiKey != null) InfoCard(R.string.api_key_exist)
if(sp.apiKey != null) Notes(R.string.api_key_exist)
}
}
}

View File

@@ -91,7 +91,7 @@ import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.Animations
import com.bintianqi.owndroid.ui.FunctionItem
import com.bintianqi.owndroid.ui.InfoCard
import com.bintianqi.owndroid.ui.Notes
import com.bintianqi.owndroid.ui.ListItem
import com.bintianqi.owndroid.ui.NavIcon
import com.bintianqi.owndroid.ui.RadioButtonItem
@@ -467,7 +467,7 @@ private fun UserControlDisabledPackagesScreen(pkgName:String) {
) {
Text(stringResource(R.string.apply))
}
InfoCard(R.string.info_disable_user_control)
Notes(R.string.info_disable_user_control)
Spacer(Modifier.padding(vertical = 30.dp))
}
}
@@ -787,7 +787,7 @@ private fun PermittedAccessibilityServicesScreen(pkgName: String) {
}
}
}
InfoCard(R.string.system_accessibility_always_allowed)
Notes(R.string.system_accessibility_always_allowed)
Spacer(Modifier.padding(vertical = 30.dp))
}
}
@@ -845,7 +845,7 @@ private fun PermittedInputMethodsScreen(pkgName: String) {
}
}
}
InfoCard(R.string.system_ime_always_allowed)
Notes(R.string.system_ime_always_allowed)
Spacer(Modifier.padding(vertical = 30.dp))
}
}
@@ -891,7 +891,7 @@ private fun KeepUninstalledPackagesScreen(pkgName: String) {
) {
Text(stringResource(R.string.apply))
}
InfoCard(R.string.info_keep_uninstalled_apps)
Notes(R.string.info_keep_uninstalled_apps)
Spacer(Modifier.padding(vertical = 30.dp))
}
}

View File

@@ -134,8 +134,9 @@ import com.bintianqi.owndroid.humanReadableDateTime
import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.CheckBoxItem
import com.bintianqi.owndroid.ui.ExpandExposedTextFieldIcon
import com.bintianqi.owndroid.ui.FullWidthRadioButtonItem
import com.bintianqi.owndroid.ui.FunctionItem
import com.bintianqi.owndroid.ui.InfoCard
import com.bintianqi.owndroid.ui.Notes
import com.bintianqi.owndroid.ui.ListItem
import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.MySmallTitleScaffold
@@ -168,7 +169,7 @@ fun NetworkScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
if(VERSION.SDK_INT >= 30) {
FunctionItem(R.string.options, icon = R.drawable.tune_fill0) { onNavigate(NetworkOptions) }
}
if(VERSION.SDK_INT >= 23 && (deviceOwner || profileOwner))
if(VERSION.SDK_INT >= 23 && !dhizuku && (deviceOwner || profileOwner))
FunctionItem(R.string.network_stats, icon = R.drawable.query_stats_fill0) { onNavigate(QueryNetworkStats) }
if(VERSION.SDK_INT >= 29 && deviceOwner) {
FunctionItem(R.string.private_dns, icon = R.drawable.dns_fill0) { onNavigate(PrivateDns) }
@@ -765,22 +766,21 @@ fun WifiSecurityLevelScreen(onNavigateUp: () -> Unit) {
val dpm = context.getDPM()
var selectedWifiSecLevel by remember { mutableIntStateOf(0) }
LaunchedEffect(Unit) { selectedWifiSecLevel = dpm.minimumRequiredWifiSecurityLevel }
MyScaffold(R.string.min_wifi_security_level, 8.dp, onNavigateUp) {
RadioButtonItem(R.string.wifi_security_open, selectedWifiSecLevel == WIFI_SECURITY_OPEN) { selectedWifiSecLevel = WIFI_SECURITY_OPEN }
RadioButtonItem("WEP, WPA(2)-PSK", selectedWifiSecLevel == WIFI_SECURITY_PERSONAL) { selectedWifiSecLevel = WIFI_SECURITY_PERSONAL }
RadioButtonItem("WPA-EAP", selectedWifiSecLevel == WIFI_SECURITY_ENTERPRISE_EAP) { selectedWifiSecLevel = WIFI_SECURITY_ENTERPRISE_EAP }
RadioButtonItem("WPA3-192bit", selectedWifiSecLevel == WIFI_SECURITY_ENTERPRISE_192) { selectedWifiSecLevel = WIFI_SECURITY_ENTERPRISE_192 }
Spacer(Modifier.padding(vertical = 5.dp))
MySmallTitleScaffold(R.string.min_wifi_security_level, 0.dp, onNavigateUp) {
FullWidthRadioButtonItem(R.string.wifi_security_open, selectedWifiSecLevel == WIFI_SECURITY_OPEN) { selectedWifiSecLevel = WIFI_SECURITY_OPEN }
FullWidthRadioButtonItem("WEP, WPA(2)-PSK", selectedWifiSecLevel == WIFI_SECURITY_PERSONAL) { selectedWifiSecLevel = WIFI_SECURITY_PERSONAL }
FullWidthRadioButtonItem("WPA-EAP", selectedWifiSecLevel == WIFI_SECURITY_ENTERPRISE_EAP) { selectedWifiSecLevel = WIFI_SECURITY_ENTERPRISE_EAP }
FullWidthRadioButtonItem("WPA3-192bit", selectedWifiSecLevel == WIFI_SECURITY_ENTERPRISE_192) { selectedWifiSecLevel = WIFI_SECURITY_ENTERPRISE_192 }
Button(
onClick = {
dpm.minimumRequiredWifiSecurityLevel = selectedWifiSecLevel
context.showOperationResultToast(true)
},
modifier = Modifier.fillMaxWidth()
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp, horizontal = 8.dp)
) {
Text(stringResource(R.string.apply))
}
InfoCard(R.string.info_minimum_wifi_security_level)
Notes(R.string.info_minimum_wifi_security_level, 8.dp)
}
}
@@ -792,26 +792,26 @@ fun WifiSsidPolicyScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val focusMgr = LocalFocusManager.current
MyScaffold(R.string.wifi_ssid_policy, 8.dp, onNavigateUp) {
MyScaffold(R.string.wifi_ssid_policy, 0.dp, onNavigateUp) {
var selectedPolicyType by remember { mutableIntStateOf(-1) }
val ssidList = remember { mutableStateListOf<WifiSsid>() }
val refreshPolicy = {
fun refreshPolicy() {
val policy = dpm.wifiSsidPolicy
ssidList.clear()
selectedPolicyType = policy?.policyType ?: -1
ssidList.addAll(policy?.ssids ?: mutableSetOf())
}
LaunchedEffect(Unit) { refreshPolicy() }
RadioButtonItem(R.string.none, selectedPolicyType == -1) { selectedPolicyType = -1 }
RadioButtonItem(R.string.whitelist, selectedPolicyType == WIFI_SSID_POLICY_TYPE_ALLOWLIST) {
FullWidthRadioButtonItem(R.string.none, selectedPolicyType == -1) { selectedPolicyType = -1 }
FullWidthRadioButtonItem(R.string.whitelist, selectedPolicyType == WIFI_SSID_POLICY_TYPE_ALLOWLIST) {
selectedPolicyType = WIFI_SSID_POLICY_TYPE_ALLOWLIST
}
RadioButtonItem(R.string.blacklist, selectedPolicyType == WIFI_SSID_POLICY_TYPE_DENYLIST) {
FullWidthRadioButtonItem(R.string.blacklist, selectedPolicyType == WIFI_SSID_POLICY_TYPE_DENYLIST) {
selectedPolicyType = WIFI_SSID_POLICY_TYPE_DENYLIST
}
AnimatedVisibility(selectedPolicyType != -1) {
var inputSsid by remember { mutableStateOf("") }
Column {
Column(Modifier.padding(horizontal = 8.dp)) {
Text(stringResource(R.string.ssid_list_is))
if(ssidList.isEmpty()) Text(stringResource(R.string.none))
Column(modifier = Modifier.animateContentSize()) {
@@ -839,7 +839,6 @@ fun WifiSsidPolicyScreen(onNavigateUp: () -> Unit) {
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
modifier = Modifier.fillMaxWidth()
)
Spacer(Modifier.padding(vertical = 10.dp))
}
}
Button(
@@ -853,7 +852,7 @@ fun WifiSsidPolicyScreen(onNavigateUp: () -> Unit) {
refreshPolicy()
context.showOperationResultToast(true)
},
modifier = Modifier.fillMaxWidth()
modifier = Modifier.fillMaxWidth().padding(8.dp)
) {
Text(stringResource(R.string.apply))
}
@@ -1291,7 +1290,7 @@ data class NetworkStatsViewer(
fun NetworkStatsViewerScreen(nsv: NetworkStatsViewer, onNavigateUp: () -> Unit) {
var index by remember { mutableIntStateOf(0) }
val size = nsv.stats.size
MySmallTitleScaffold(R.string.place_holder, 8.dp, onNavigateUp) {
MySmallTitleScaffold(R.string.network_stats, 8.dp, onNavigateUp) {
if(size > 1) Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.align(Alignment.CenterHorizontally).padding(bottom = 8.dp)
@@ -1318,15 +1317,13 @@ fun NetworkStatsViewerScreen(nsv: NetworkStatsViewer, onNavigateUp: () -> Unit)
val txBytes = data.txBytes
Text(stringResource(R.string.transmitted), style = typography.titleLarge)
Column(modifier = Modifier.padding(start = 8.dp, bottom = 4.dp)) {
Text("$txBytes bytes")
Text(formatFileSize(txBytes))
Text("$txBytes bytes (${formatFileSize(txBytes)})")
Text(data.txPackets.toString() + " packets")
}
val rxBytes = data.rxBytes
Text(stringResource(R.string.received), style = typography.titleLarge)
Column(modifier = Modifier.padding(start = 8.dp, bottom = 8.dp)) {
Text("$rxBytes bytes")
Text(formatFileSize(rxBytes))
Text("$rxBytes bytes (${formatFileSize(rxBytes)})")
Text(data.rxPackets.toString() + " packets")
}
Row(verticalAlignment = Alignment.CenterVertically) {
@@ -1406,7 +1403,7 @@ fun PrivateDnsScreen(onNavigateUp: () -> Unit) {
Text(stringResource(R.string.set_to_opportunistic))
}
}
InfoCard(R.string.info_private_dns_mode_oppertunistic)
Notes(R.string.info_private_dns_mode_oppertunistic)
Spacer(Modifier.padding(vertical = 10.dp))
var inputHost by remember { mutableStateOf(dpm.getGlobalPrivateDnsHost(receiver) ?: "") }
OutlinedTextField(
@@ -1439,7 +1436,7 @@ fun PrivateDnsScreen(onNavigateUp: () -> Unit) {
) {
Text(stringResource(R.string.set_dns_host))
}
InfoCard(R.string.info_set_private_dns_host)
Notes(R.string.info_set_private_dns_host)
}
}
@@ -1505,7 +1502,7 @@ fun AlwaysOnVpnPackageScreen(onNavigateUp: () -> Unit) {
) {
Text(stringResource(R.string.clear_current_config))
}
InfoCard(R.string.info_always_on_vpn)
Notes(R.string.info_always_on_vpn)
}
}
@@ -1604,7 +1601,7 @@ fun RecommendedGlobalProxyScreen(onNavigateUp: () -> Unit) {
) {
Text(stringResource(R.string.apply))
}
InfoCard(R.string.info_recommended_global_proxy)
Notes(R.string.info_recommended_global_proxy)
}
}
@@ -1656,7 +1653,7 @@ fun NetworkLoggingScreen(onNavigateUp: () -> Unit) {
Text(stringResource(R.string.delete_logs))
}
}
InfoCard(R.string.info_network_log)
Notes(R.string.info_network_log)
}
}

View File

@@ -73,7 +73,7 @@ import com.bintianqi.owndroid.ui.CheckBoxItem
import com.bintianqi.owndroid.ui.FullWidthCheckBoxItem
import com.bintianqi.owndroid.ui.FullWidthRadioButtonItem
import com.bintianqi.owndroid.ui.FunctionItem
import com.bintianqi.owndroid.ui.InfoCard
import com.bintianqi.owndroid.ui.Notes
import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.RadioButtonItem
import com.bintianqi.owndroid.yesOrNo
@@ -308,7 +308,7 @@ fun ResetPasswordTokenScreen(onNavigateUp: () -> Unit) {
}
}
Spacer(Modifier.padding(vertical = 5.dp))
InfoCard(R.string.activate_token_not_required_when_no_password)
Notes(R.string.activate_token_not_required_when_no_password)
}
}
@@ -386,7 +386,7 @@ fun ResetPasswordScreen(onNavigateUp: () -> Unit) {
Text(stringResource(R.string.reset_password))
}
}
InfoCard(R.string.info_reset_password)
Notes(R.string.info_reset_password)
}
if(confirmDialog) {
var confirmPassword by remember { mutableStateOf("") }
@@ -462,7 +462,7 @@ fun RequiredPasswordComplexityScreen(onNavigateUp: () -> Unit) {
) {
Text(text = stringResource(R.string.apply))
}
InfoCard(R.string.info_password_complexity, 8.dp)
Notes(R.string.info_password_complexity, 8.dp)
}
}
@@ -519,7 +519,7 @@ fun KeyguardDisabledFeaturesScreen(onNavigateUp: () -> Unit) {
refresh()
context.showOperationResultToast(true)
},
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp)
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp, horizontal = 8.dp)
) {
Text(text = stringResource(R.string.apply))
}

View File

@@ -306,7 +306,7 @@ fun LockScreenInfoScreen(onNavigateUp: () -> Unit) {
Text(text = stringResource(R.string.reset))
}
Spacer(Modifier.padding(vertical = 10.dp))
InfoCard(R.string.info_lock_screen_info)
Notes(R.string.info_lock_screen_info)
}
}
@@ -716,7 +716,7 @@ fun SupportMessageScreen(onNavigateUp: () -> Unit) {
Text(text = stringResource(R.string.reset))
}
}
InfoCard(R.string.info_short_support_message)
Notes(R.string.info_short_support_message)
Spacer(Modifier.padding(vertical = 8.dp))
OutlinedTextField(
value = longMsg,
@@ -747,7 +747,7 @@ fun SupportMessageScreen(onNavigateUp: () -> Unit) {
Text(text = stringResource(R.string.reset))
}
}
InfoCard(R.string.info_long_support_message)
Notes(R.string.info_long_support_message)
}
}
@@ -778,7 +778,7 @@ fun TransferOwnershipScreen(onNavigateUp: () -> Unit) {
Text(stringResource(R.string.transfer))
}
Spacer(Modifier.padding(vertical = 10.dp))
InfoCard(R.string.info_transfer_ownership)
Notes(R.string.info_transfer_ownership)
}
if(dialog) AlertDialog(
text = {

View File

@@ -6,13 +6,6 @@ import android.app.AlertDialog
import android.app.admin.DevicePolicyManager
import android.app.admin.DevicePolicyManager.FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY
import android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback
import android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK
import android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS
import android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_HOME
import android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD
import android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS
import android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW
import android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO
import android.app.admin.DevicePolicyManager.MTE_DISABLED
import android.app.admin.DevicePolicyManager.MTE_ENABLED
import android.app.admin.DevicePolicyManager.MTE_NOT_CONTROLLED_BY_POLICY
@@ -46,6 +39,7 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState
@@ -56,9 +50,7 @@ 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.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.pager.HorizontalPager
@@ -134,14 +126,14 @@ import com.bintianqi.owndroid.humanReadableDate
import com.bintianqi.owndroid.parseDate
import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.CheckBoxItem
import com.bintianqi.owndroid.ui.FullWidthCheckBoxItem
import com.bintianqi.owndroid.ui.FullWidthRadioButtonItem
import com.bintianqi.owndroid.ui.FunctionItem
import com.bintianqi.owndroid.ui.InfoCard
import com.bintianqi.owndroid.ui.ListItem
import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.MySmallTitleScaffold
import com.bintianqi.owndroid.ui.NavIcon
import com.bintianqi.owndroid.ui.RadioButtonItem
import com.bintianqi.owndroid.ui.Notes
import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.uriToStream
import kotlinx.coroutines.Dispatchers
@@ -370,7 +362,7 @@ fun KeyguardScreen(onNavigateUp: () -> Unit) {
Text(stringResource(R.string.enable))
}
}
InfoCard(R.string.info_disable_keyguard)
Notes(R.string.info_disable_keyguard)
Spacer(Modifier.padding(vertical = 12.dp))
}
if(VERSION.SDK_INT >= 23) Text(text = stringResource(R.string.lock_now), style = typography.headlineLarge)
@@ -393,7 +385,7 @@ fun KeyguardScreen(onNavigateUp: () -> Unit) {
Text(stringResource(R.string.lock_now))
}
if(VERSION.SDK_INT >= 26 && profileOwner && dpm.isManagedProfile(receiver)) {
InfoCard(R.string.info_evict_credential_encryption_key)
Notes(R.string.info_evict_credential_encryption_key)
}
}
}
@@ -491,10 +483,7 @@ fun ChangeTimeScreen(onNavigateUp: () -> Unit) {
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
val coroutine = rememberCoroutineScope()
val pagerState = rememberPagerState { 2 }
var manualInput by remember { mutableStateOf(false) }
var inputTime by remember { mutableStateOf("")}
var picker by remember { mutableIntStateOf(0) } //0:None, 1:DatePicker, 2:TimePicker
val datePickerState = rememberDatePickerState()
val timePickerState = rememberTimePickerState()
@@ -502,16 +491,14 @@ fun ChangeTimeScreen(onNavigateUp: () -> Unit) {
val timeInteractionSource = remember { MutableInteractionSource() }
if(dateInteractionSource.collectIsPressedAsState().value) picker = 1
if(timeInteractionSource.collectIsPressedAsState().value) picker = 2
val isInputLegal = (manualInput && (try { inputTime.toLong() } catch(_: Exception) { -1 }) >= 0) ||
(!manualInput && datePickerState.selectedDateMillis != null)
MyScaffold(R.string.change_time, 8.dp, onNavigateUp) {
SingleChoiceSegmentedButtonRow(
modifier = Modifier.fillMaxWidth().padding(top = 4.dp)
) {
val coroutine = rememberCoroutineScope()
SegmentedButton(
selected = !manualInput, shape = SegmentedButtonDefaults.itemShape(0, 2),
selected = pagerState.targetPage == 0, shape = SegmentedButtonDefaults.itemShape(0, 2),
onClick = {
manualInput = false
coroutine.launch {
pagerState.animateScrollToPage(0)
}
@@ -520,9 +507,8 @@ fun ChangeTimeScreen(onNavigateUp: () -> Unit) {
Text(stringResource(R.string.selector))
}
SegmentedButton(
selected = manualInput, shape = SegmentedButtonDefaults.itemShape(1, 2),
selected = pagerState.targetPage == 1, shape = SegmentedButtonDefaults.itemShape(1, 2),
onClick = {
manualInput = true
coroutine.launch {
pagerState.animateScrollToPage(1)
}
@@ -532,10 +518,11 @@ fun ChangeTimeScreen(onNavigateUp: () -> Unit) {
}
}
HorizontalPager(
state = pagerState, modifier = Modifier.height(140.dp).padding(top = 4.dp),
state = pagerState, modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.Top
) { page ->
if(page == 0) Column {
Column(Modifier.padding(top = 4.dp)) {
if(page == 0) {
OutlinedTextField(
value = datePickerState.selectedDateMillis?.humanReadableDate ?: "",
onValueChange = {}, readOnly = true,
@@ -548,31 +535,42 @@ fun ChangeTimeScreen(onNavigateUp: () -> Unit) {
onValueChange = {}, readOnly = true,
label = { Text(stringResource(R.string.time)) },
interactionSource = timeInteractionSource,
modifier = Modifier.fillMaxWidth()
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp)
)
Button(
onClick = {
val timeMillis = datePickerState.selectedDateMillis!! + timePickerState.hour * 3600000 + timePickerState.minute * 60000
context.showOperationResultToast(dpm.setTime(receiver, timeMillis))
},
modifier = Modifier.fillMaxWidth(),
enabled = datePickerState.selectedDateMillis != null
) {
Text(stringResource(R.string.apply))
}
if(page == 1) OutlinedTextField(
} else {
var inputTime by remember { mutableStateOf("") }
OutlinedTextField(
value = inputTime,
label = { Text(stringResource(R.string.time_unit_ms)) },
onValueChange = { inputTime = it },
supportingText = { Text(stringResource(R.string.info_change_time)) },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
modifier = Modifier.fillMaxWidth()
)
}
Button(
onClick = {
val timeMillis = if(manualInput) inputTime.toLong()
else datePickerState.selectedDateMillis!! + timePickerState.hour * 3600000 + timePickerState.minute * 60000
val timeMillis = inputTime.toLong()
context.showOperationResultToast(dpm.setTime(receiver, timeMillis))
},
modifier = Modifier.fillMaxWidth(),
enabled = isInputLegal
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp),
enabled = inputTime.toLongOrNull() != null
) {
Text(stringResource(R.string.apply))
}
}
}
}
}
if(picker == 1) DatePickerDialog(
confirmButton = {
TextButton(onClick = { picker = 0; focusMgr.clearFocus() } ) {
@@ -629,7 +627,7 @@ fun ChangeTimeZoneScreen(onNavigateUp: () -> Unit) {
Text(stringResource(R.string.apply))
}
Spacer(Modifier.padding(vertical = 10.dp))
InfoCard(R.string.disable_auto_time_zone_before_set)
Notes(R.string.disable_auto_time_zone_before_set)
}
if(dialog) AlertDialog(
text = {
@@ -868,7 +866,7 @@ fun ContentProtectionPolicyScreen(onNavigateUp: () -> Unit) {
) {
Text(stringResource(R.string.apply))
}
InfoCard(R.string.info_content_protection_policy, 8.dp)
Notes(R.string.info_content_protection_policy, 8.dp)
}
}
@@ -901,7 +899,7 @@ fun PermissionPolicyScreen(onNavigateUp: () -> Unit) {
) {
Text(stringResource(R.string.apply))
}
InfoCard(R.string.info_permission_policy, 8.dp)
Notes(R.string.info_permission_policy, 8.dp)
}
}
@@ -933,7 +931,7 @@ fun MtePolicyScreen(onNavigateUp: () -> Unit) {
) {
Text(stringResource(R.string.apply))
}
InfoCard(R.string.info_mte_policy, 8.dp)
Notes(R.string.info_mte_policy, 8.dp)
}
}
@@ -945,7 +943,7 @@ fun NearbyStreamingPolicyScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
var appPolicy by remember { mutableIntStateOf(dpm.nearbyAppStreamingPolicy) }
MyScaffold(R.string.nearby_streaming_policy, 0.dp, onNavigateUp) {
MySmallTitleScaffold(R.string.nearby_streaming_policy, 0.dp, onNavigateUp) {
Text(
stringResource(R.string.nearby_app_streaming),
Modifier.padding(start = 8.dp, top = 10.dp, bottom = 4.dp), style = typography.titleLarge
@@ -970,7 +968,7 @@ fun NearbyStreamingPolicyScreen(onNavigateUp: () -> Unit) {
) {
Text(stringResource(R.string.apply))
}
InfoCard(R.string.info_nearby_app_streaming_policy, 8.dp)
Notes(R.string.info_nearby_app_streaming_policy, 8.dp)
var notificationPolicy by remember { mutableIntStateOf(dpm.nearbyNotificationStreamingPolicy) }
Text(
stringResource(R.string.nearby_notification_streaming),
@@ -1002,7 +1000,7 @@ fun NearbyStreamingPolicyScreen(onNavigateUp: () -> Unit) {
) {
Text(stringResource(R.string.apply))
}
InfoCard(R.string.info_nearby_notification_streaming_policy, 8.dp)
Notes(R.string.info_nearby_notification_streaming_policy, 8.dp)
}
}
@@ -1043,12 +1041,19 @@ fun LockTaskModeScreen(onNavigateUp: () -> Unit) {
)
}
HorizontalPager(pagerState, verticalAlignment = Alignment.Top) { page ->
if(page == 0 || page == 1) {
Column(
modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(start = 8.dp, end = 8.dp, bottom = 80.dp)
) {
if(page == 0) StartLockTaskMode()
else if(page == 1) LockTaskPackages()
else LockTaskFeatures()
else LockTaskPackages()
}
} else {
Column(
modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(bottom = 80.dp)
) {
LockTaskFeatures()
}
}
}
}
@@ -1116,7 +1121,7 @@ private fun ColumnScope.StartLockTaskMode() {
) {
Text(stringResource(R.string.start))
}
InfoCard(R.string.info_start_lock_task_mode)
Notes(R.string.info_start_lock_task_mode)
}
@RequiresApi(26)
@@ -1181,7 +1186,7 @@ private fun ColumnScope.LockTaskPackages() {
) {
Text(stringResource(R.string.apply))
}
InfoCard(R.string.info_lock_task_packages)
Notes(R.string.info_lock_task_packages)
}
@RequiresApi(28)
@@ -1198,44 +1203,28 @@ private fun ColumnScope.LockTaskFeatures() {
}
LaunchedEffect(Unit) { refresh() }
Spacer(Modifier.padding(vertical = 5.dp))
RadioButtonItem(R.string.disable_all, !custom) { custom = false }
RadioButtonItem(R.string.custom, custom) { custom = true }
AnimatedVisibility(custom) {
FullWidthRadioButtonItem(R.string.disable_all, !custom) { custom = false }
FullWidthRadioButtonItem(R.string.custom, custom) { custom = true }
AnimatedVisibility(custom, Modifier.padding(top = 4.dp)) {
Column {
CheckBoxItem(
R.string.ltf_sys_info,
flags and LOCK_TASK_FEATURE_SYSTEM_INFO != 0
) { flags = flags xor LOCK_TASK_FEATURE_SYSTEM_INFO }
CheckBoxItem(
R.string.ltf_notifications,
flags and LOCK_TASK_FEATURE_NOTIFICATIONS != 0
) { flags = flags xor LOCK_TASK_FEATURE_NOTIFICATIONS }
CheckBoxItem(
R.string.ltf_home,
flags and LOCK_TASK_FEATURE_HOME != 0
) { flags = flags xor LOCK_TASK_FEATURE_HOME }
CheckBoxItem(
R.string.ltf_overview,
flags and LOCK_TASK_FEATURE_OVERVIEW != 0
) { flags = flags xor LOCK_TASK_FEATURE_OVERVIEW }
CheckBoxItem(
R.string.ltf_global_actions,
flags and LOCK_TASK_FEATURE_GLOBAL_ACTIONS != 0
) { flags = flags xor LOCK_TASK_FEATURE_GLOBAL_ACTIONS }
CheckBoxItem(
R.string.ltf_keyguard,
flags and LOCK_TASK_FEATURE_KEYGUARD != 0
) { flags = flags xor LOCK_TASK_FEATURE_KEYGUARD }
if(VERSION.SDK_INT >= 30) {
CheckBoxItem(
R.string.ltf_block_activity_start_in_task,
flags and LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK != 0
) { flags = flags xor LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK }
listOf(
DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO to R.string.ltf_sys_info,
DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS to R.string.ltf_notifications,
DevicePolicyManager.LOCK_TASK_FEATURE_HOME to R.string.ltf_home,
DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW to R.string.ltf_overview,
DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS to R.string.ltf_global_actions,
DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD to R.string.ltf_keyguard
).let {
if(VERSION.SDK_INT >= 30)
it.plus(DevicePolicyManager.LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK to R.string.ltf_block_activity_start_in_task)
else it
}.forEach { (id, title) ->
FullWidthCheckBoxItem(title, flags and id != 0) { flags = flags xor id }
}
}
}
Button(
modifier = Modifier.fillMaxWidth(),
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp, horizontal = 8.dp),
onClick = {
try {
dpm.setLockTaskFeatures(receiver, flags)
@@ -1469,7 +1458,7 @@ fun SecurityLoggingScreen(onNavigateUp: () -> Unit) {
Text(stringResource(R.string.delete_logs))
}
}
InfoCard(R.string.info_security_log)
Notes(R.string.info_security_log)
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = {
@@ -1490,7 +1479,7 @@ fun SecurityLoggingScreen(onNavigateUp: () -> Unit) {
) {
Text(stringResource(R.string.pre_reboot_security_logs))
}
InfoCard(R.string.info_pre_reboot_security_log)
Notes(R.string.info_pre_reboot_security_log)
}
}
@@ -1540,7 +1529,7 @@ fun DisableAccountManagementScreen(onNavigateUp: () -> Unit) {
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() })
)
Spacer(Modifier.padding(vertical = 10.dp))
InfoCard(R.string.info_disable_account_management)
Notes(R.string.info_disable_account_management)
}
}
@@ -1559,7 +1548,7 @@ fun FrpPolicyScreen(onNavigateUp: () -> Unit) {
val accountList = remember { mutableStateListOf<String>() }
var inputAccount by remember { mutableStateOf("") }
LaunchedEffect(Unit) {
var policy: FactoryResetProtectionPolicy? = FactoryResetProtectionPolicy.Builder().build()
var policy: FactoryResetProtectionPolicy? = null
try {
policy = dpm.getFactoryResetProtectionPolicy(receiver)
} catch(_: UnsupportedOperationException) {
@@ -1575,6 +1564,14 @@ fun FrpPolicyScreen(onNavigateUp: () -> Unit) {
}
}
MyScaffold(R.string.frp_policy, 8.dp, onNavigateUp) {
if(unsupported) {
Column(
Modifier.fillMaxWidth().padding(vertical = 8.dp)
.clip(RoundedCornerShape(8.dp)).background(colorScheme.primaryContainer)
) {
Text(stringResource(R.string.frp_not_supported), Modifier.padding(8.dp), color = colorScheme.onPrimaryContainer)
}
} else {
Row(
horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth().padding(horizontal = 6.dp, vertical = 8.dp)
@@ -1582,6 +1579,7 @@ fun FrpPolicyScreen(onNavigateUp: () -> Unit) {
Text(stringResource(R.string.use_policy), style = typography.titleLarge)
Switch(checked = usePolicy, onCheckedChange = { usePolicy = it })
}
}
AnimatedVisibility(usePolicy) {
Column {
CheckBoxItem(R.string.enable_frp, enabled) { enabled = it }
@@ -1611,31 +1609,22 @@ fun FrpPolicyScreen(onNavigateUp: () -> Unit) {
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
modifier = Modifier.fillMaxWidth()
)
Spacer(Modifier.padding(vertical = 2.dp))
}
}
Spacer(Modifier.padding(vertical = 5.dp))
Button(
if(!unsupported) Button(
onClick = {
focusMgr.clearFocus()
if(unsupported) {
Toast.makeText(context, R.string.unsupported, Toast.LENGTH_SHORT).show()
} else {
val policy = FactoryResetProtectionPolicy.Builder()
.setFactoryResetProtectionEnabled(enabled)
.setFactoryResetProtectionAccounts(accountList)
.build()
dpm.setFactoryResetProtectionPolicy(receiver, policy)
}
},
modifier = Modifier.width(100.dp).align(Alignment.CenterHorizontally)
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp)
) {
Text(stringResource(R.string.apply))
}
Spacer(Modifier.padding(vertical = 10.dp))
if(unsupported) Text(stringResource(R.string.frp_policy_not_supported))
Spacer(Modifier.padding(vertical = 6.dp))
InfoCard(R.string.info_frp_policy)
Notes(R.string.info_frp_policy)
}
}
@@ -1885,6 +1874,6 @@ fun InstallSystemUpdateScreen(onNavigateUp: () -> Unit) {
}
}
Spacer(Modifier.padding(vertical = 10.dp))
InfoCard(R.string.auto_reboot_after_install_succeed)
Notes(R.string.auto_reboot_after_install_succeed)
}
}

View File

@@ -37,6 +37,7 @@ fun UserRestrictionScreen(onNavigateUp: () -> Unit, onNavigate: (Int, List<Restr
val dpm = context.getDPM()
val receiver = context.getReceiver()
MyScaffold(R.string.user_restriction, 0.dp, onNavigateUp) {
Spacer(Modifier.padding(vertical = 2.dp))
Text(text = stringResource(R.string.switch_to_disable_feature), modifier = Modifier.padding(start = 16.dp))
if(context.isProfileOwner) { Text(text = stringResource(R.string.profile_owner_is_restricted), modifier = Modifier.padding(start = 16.dp)) }
if(context.isProfileOwner && dpm.isManagedProfile(receiver)) {

View File

@@ -70,7 +70,7 @@ import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.CardItem
import com.bintianqi.owndroid.ui.CheckBoxItem
import com.bintianqi.owndroid.ui.FunctionItem
import com.bintianqi.owndroid.ui.InfoCard
import com.bintianqi.owndroid.ui.Notes
import com.bintianqi.owndroid.ui.ListItem
import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.SwitchItem
@@ -457,7 +457,7 @@ fun AffiliationIdScreen(onNavigateUp: () -> Unit) {
) {
Text(stringResource(R.string.apply))
}
InfoCard(R.string.info_affiliation_id)
Notes(R.string.info_affiliation_id)
}
}

View File

@@ -59,7 +59,7 @@ import com.bintianqi.owndroid.ui.CardItem
import com.bintianqi.owndroid.ui.CheckBoxItem
import com.bintianqi.owndroid.ui.CopyTextButton
import com.bintianqi.owndroid.ui.FunctionItem
import com.bintianqi.owndroid.ui.InfoCard
import com.bintianqi.owndroid.ui.Notes
import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.yesOrNo
@@ -230,7 +230,7 @@ fun SuspendPersonalAppScreen(onNavigateUp: () -> Unit) {
) {
Text(stringResource(R.string.apply))
}
InfoCard(R.string.info_profile_maximum_time_off)
Notes(R.string.info_profile_maximum_time_off)
}
}
@@ -280,7 +280,7 @@ fun CrossProfileIntentFilterScreen(onNavigateUp: () -> Unit) {
) {
Text(stringResource(R.string.clear_cross_profile_filters))
}
InfoCard(R.string.info_cross_profile_intent_filter)
Notes(R.string.info_cross_profile_intent_filter)
}
}

View File

@@ -104,13 +104,20 @@ fun FullWidthRadioButtonItem(
text: Int,
selected: Boolean,
operation: () -> Unit
) = FullWidthRadioButtonItem(stringResource(text), selected, operation)
@Composable
fun FullWidthRadioButtonItem(
text: String,
selected: Boolean,
operation: () -> Unit
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth().clickable(onClick = operation)
) {
RadioButton(selected = selected, onClick = operation, modifier = Modifier.padding(horizontal = 4.dp))
Text(text = stringResource(text), modifier = Modifier.padding(bottom = if(zhCN) { 2 } else { 0 }.dp))
Text(text = text, modifier = Modifier.padding(bottom = if(zhCN) { 2 } else { 0 }.dp))
}
}
@@ -272,18 +279,12 @@ fun ListItem(text: String, onDelete: () -> Unit) {
}
@Composable
fun InfoCard(@StringRes strID: Int, horizonPadding: Dp = 0.dp) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp, horizontal = horizonPadding)
.clip(RoundedCornerShape(12.dp))
.background(color = colorScheme.tertiaryContainer)
.padding(8.dp)
) {
Icon(imageVector = Icons.Outlined.Info, contentDescription = null, modifier = Modifier.padding(vertical = 4.dp))
Text(stringResource(strID))
}
fun Notes(@StringRes strID: Int, horizonPadding: Dp = 0.dp) {
Icon(Icons.Outlined.Info, null, Modifier.padding(horizontal = horizonPadding).padding(top = 4.dp, bottom = 8.dp))
Text(
stringResource(strID), Modifier.padding(horizontal = horizonPadding),
color = colorScheme.onSurfaceVariant, style = typography.bodyMedium
)
}
@OptIn(ExperimentalMaterial3Api::class)

View File

@@ -211,7 +211,7 @@
<string name="wipe_work_profile_warning">Ваш рабочий профиль будет УДАЛЕН</string>
<string name="encryption_status">Статус шифрования</string>
<string name="frp_policy">Политика FRP</string>
<string name="frp_policy_not_supported">Политика FRP не поддерживается на этом устройстве</string>
<string name="frp_not_supported">Your device does not support FRP</string> <!--TODO-->
<string name="enable_frp">Включить FRP</string>
<string name="account_list_is">Список аккаунтов: </string>
@@ -679,7 +679,6 @@
<string name="info_disable_keyguard">Отключение Keyguard имеет такой же эффект как и выбор \"Нет\" в качестве способа блокировки экрана. Однако этот вызов не имеет эффекта, если в данный момент установлен пароль, PIN-код или графический ключ.\nЕсли пароль, PIN-код или графический ключ были установлены после того как Keyguard был выключен, то Keyguard перестаёт быть выключенным.</string>
<string name="info_evict_credential_encryption_key">Удаляет ключ шифрования учетных данных пользователя из связки ключей. Потребуется повторно ввести учетные данные пользователя, чтобы получить ключ шифрования учетных данных, который будет сохранен в связке ключей для дальнейшего использования. В целях защиты пользовательских данных пользователь будет остановлен и перезапущен.</string>
<string name="info_reboot">Вы не можете использовать данную функцию, если на устройстве есть активный вызов (звонок).</string>
<string name="info_change_time">Введите время UNIX в миллисекундах</string>
<string name="info_content_protection_policy">Политика защиты контента управляет сканированием на наличие мошеннических приложений.</string>
<string name="info_permission_policy">Выбрать действие по умолчанию для запросов разрешений от приложений.</string>
<string name="info_mte_policy">Установить политику Memory Tagging Extension. Перезагрузите устройство, чтобы применить изменения.</string>

View File

@@ -218,7 +218,7 @@
<string name="wipe_work_profile_warning">Your work profile will be DELETED</string> <!--TODO-->
<string name="encryption_status">Encryption status</string> <!--TODO-->
<string name="frp_policy">FRP politikası</string>
<string name="frp_policy_not_supported">FRP politikası bu cihazda desteklenmiyor</string>
<string name="frp_not_supported">Your device does not support FRP</string> <!--TODO-->
<string name="enable_frp">FRP\'yi etkinleştir</string>
<string name="account_list_is">"Hesap listesi: "</string>

View File

@@ -208,7 +208,7 @@
<string name="wipe_work_profile_warning">你的工作资料将会被删除</string>
<string name="encryption_status">加密状态</string>
<string name="frp_policy">FRP策略</string>
<string name="frp_policy_not_supported">这个设备不支持恢复出厂设置保护策略</string>
<string name="frp_not_supported">你的设备不支持FRP策略</string>
<string name="enable_frp">启用FRP</string>
<string name="account_list_is">账户列表:</string>
@@ -661,7 +661,6 @@
<string name="info_disable_keyguard">禁用锁屏相当于把锁屏方式设置为“无”。在已设置密码或图案时使用这个功能无效。如果在锁屏禁用时设置密码或图案,锁屏将启用</string>
<string name="info_evict_credential_encryption_key">从密钥环中移除用户的凭证加密密钥。用户需要再次输入凭证才能将密钥存储回密钥环中。为了保护用户数据,用户将重新启动</string>
<string name="info_reboot">打电话时不能使用此功能</string>
<string name="info_change_time">输入以毫秒为单位的UNIX时间</string>
<string name="info_content_protection_policy">内容保护策略控制对欺骗性应用程序的扫描。</string>
<string name="info_permission_policy">设置应用申请运行时权限时的默认选择</string>
<string name="info_mte_policy">设置内存标记扩展(Memory Tagging Extension)策略。重启设备以应用更改。</string>

View File

@@ -237,7 +237,7 @@
<string name="wipe_work_profile_warning">Your work profile will be DELETED</string>
<string name="encryption_status">Encryption status</string>
<string name="frp_policy">FRP policy</string>
<string name="frp_policy_not_supported">FRP policy is not supported on this device</string>
<string name="frp_not_supported">Your device does not support FRP</string>
<string name="enable_frp">Enable FRP</string>
<string name="account_list_is">"Account list: "</string>
@@ -701,7 +701,6 @@
<string name="info_disable_keyguard">Setting the keyguard to disabled has the same effect as choosing "None" as the screen lock type. However, this call has no effect if a password, pin or pattern is currently set.\nIf a password, pin or pattern is set after the keyguard was disabled, the keyguard stops being disabled.</string>
<string name="info_evict_credential_encryption_key">Evict the user\'s credential encryption key from the keyring. The user\'s credential will need to be entered again in order to derive the credential encryption key that will be stored back in the keyring for future use. In order to secure user data, the user will be stopped and restarted.</string>
<string name="info_reboot">You can\'t use this function if there is an ongoing call on the device.</string>
<string name="info_change_time">Input UNIX time in milliseconds</string>
<string name="info_content_protection_policy">Content protection policy controls scanning for deceptive apps.</string>
<string name="info_permission_policy">Set the default response for future runtime permission requests by applications.</string>
<string name="info_mte_policy">Set the Memory Tagging Extension policy. Reboot the device to apply changes.</string>

View File

@@ -1,14 +1,14 @@
[versions]
agp = "8.8.0"
agp = "8.8.2"
kotlin = "2.0.21"
navigation-compose = "2.8.6"
composeBom = "2025.01.01"
navigation-compose = "2.8.8"
composeBom = "2025.02.00"
accompanist-drawablepainter = "0.35.0-alpha"
accompanist-permissions = "0.37.0"
shizuku = "13.1.5"
biometric = "1.2.0-alpha05"
fragment = "1.8.5"
fragment = "1.8.6"
dhizuku = "2.5.3"
hiddenApiBypass = "4.3"
serialization = "1.7.3"