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

@@ -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,45 +518,57 @@ 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 {
OutlinedTextField(
value = datePickerState.selectedDateMillis?.humanReadableDate ?: "",
onValueChange = {}, readOnly = true,
label = { Text(stringResource(R.string.date)) },
interactionSource = dateInteractionSource,
modifier = Modifier.fillMaxWidth()
)
OutlinedTextField(
value = timePickerState.hour.toString() + ":" + timePickerState.minute.toString(),
onValueChange = {}, readOnly = true,
label = { Text(stringResource(R.string.time)) },
interactionSource = timeInteractionSource,
modifier = Modifier.fillMaxWidth()
)
Column(Modifier.padding(top = 4.dp)) {
if(page == 0) {
OutlinedTextField(
value = datePickerState.selectedDateMillis?.humanReadableDate ?: "",
onValueChange = {}, readOnly = true,
label = { Text(stringResource(R.string.date)) },
interactionSource = dateInteractionSource,
modifier = Modifier.fillMaxWidth()
)
OutlinedTextField(
value = timePickerState.hour.toString() + ":" + timePickerState.minute.toString(),
onValueChange = {}, readOnly = true,
label = { Text(stringResource(R.string.time)) },
interactionSource = timeInteractionSource,
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))
}
} else {
var inputTime by remember { mutableStateOf("") }
OutlinedTextField(
value = inputTime,
label = { Text(stringResource(R.string.time_unit_ms)) },
onValueChange = { inputTime = it },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
modifier = Modifier.fillMaxWidth()
)
Button(
onClick = {
val timeMillis = inputTime.toLong()
context.showOperationResultToast(dpm.setTime(receiver, timeMillis))
},
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp),
enabled = inputTime.toLongOrNull() != null
) {
Text(stringResource(R.string.apply))
}
}
}
if(page == 1) 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
context.showOperationResultToast(dpm.setTime(receiver, timeMillis))
},
modifier = Modifier.fillMaxWidth(),
enabled = isInputLegal
) {
Text(stringResource(R.string.apply))
}
}
if(picker == 1) DatePickerDialog(
@@ -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 ->
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()
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 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,12 +1564,21 @@ fun FrpPolicyScreen(onNavigateUp: () -> Unit) {
}
}
MyScaffold(R.string.frp_policy, 8.dp, onNavigateUp) {
Row(
horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth().padding(horizontal = 6.dp, vertical = 8.dp)
) {
Text(stringResource(R.string.use_policy), style = typography.titleLarge)
Switch(checked = usePolicy, onCheckedChange = { usePolicy = it })
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)
) {
Text(stringResource(R.string.use_policy), style = typography.titleLarge)
Switch(checked = usePolicy, onCheckedChange = { usePolicy = it })
}
}
AnimatedVisibility(usePolicy) {
Column {
@@ -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)
}
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)