Timezone ID selector

Use IconButton to save/delete preferential network config
Fix horizontal padding across SubPageItem and SwitchItem
Delete User guide link in About
This commit is contained in:
BinTianqi
2024-11-23 19:47:47 +08:00
parent 2c1898e4a0
commit c408e3b8ce
11 changed files with 115 additions and 129 deletions

View File

@@ -91,9 +91,7 @@ class MainActivity : FragmentActivity() {
val context = applicationContext
val sharedPref = context.getSharedPreferences("data", MODE_PRIVATE)
if (VERSION.SDK_INT >= 28) HiddenApiBypass.setHiddenApiExemptions("")
if(sharedPref.getBoolean("auth", false)) {
showAuth.value = true
}
if(sharedPref.getBoolean("auth", false)) showAuth.value = true
val locale = context.resources?.configuration?.locale
zhCN = locale == Locale.SIMPLIFIED_CHINESE || locale == Locale.CHINESE || locale == Locale.CHINA
toggleInstallAppActivity()

View File

@@ -118,7 +118,7 @@ private fun ThemeSettings(vm: MyViewModel) {
SubPageItem(R.string.dark_theme, stringResource(darkThemeTextID)) { darkThemeMenu = true }
DropdownMenu(
expanded = darkThemeMenu, onDismissRequest = { darkThemeMenu = false },
offset = DpOffset(x = 30.dp, y = 0.dp)
offset = DpOffset(x = 25.dp, y = 0.dp)
) {
DropdownMenuItem(
text = { Text(stringResource(R.string.follow_system)) },
@@ -240,7 +240,6 @@ private fun About() {
Spacer(Modifier.padding(vertical = 5.dp))
Text(text = stringResource(R.string.app_name)+" v$verName ($verCode)", modifier = Modifier.padding(start = 26.dp))
Spacer(Modifier.padding(vertical = 5.dp))
SubPageItem(R.string.user_guide, "", R.drawable.open_in_new) { shareLink(context, "https://owndroid.pages.dev") }
SubPageItem(R.string.source_code, "", R.drawable.open_in_new) { shareLink(context, "https://github.com/BinTianqi/OwnDroid") }
}
}

View File

@@ -45,7 +45,6 @@ import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.clickable
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -58,12 +57,12 @@ 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.text.selection.SelectionContainer
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.Icon
@@ -826,8 +825,11 @@ fun PreferentialNetworkService() {
)
}
}
Row {
Button(
Row(
horizontalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth()
) {
IconButton(
onClick = {
try {
saveCurrentConfig()
@@ -837,19 +839,18 @@ fun PreferentialNetworkService() {
Toast.makeText(context, R.string.failed_to_save_current_config, Toast.LENGTH_SHORT).show()
}
},
modifier = Modifier.fillMaxWidth(0.49F)
modifier = Modifier.padding(end = 10.dp)
) {
Text(stringResource(R.string.save_current_config))
Icon(painter = painterResource(R.drawable.save_fill0), contentDescription = stringResource(R.string.save_current_config))
}
Button(
IconButton(
onClick = {
if(index < configs.size) configs.removeAt(index)
if(index > 0) index -= 1
refresh()
},
modifier = Modifier.fillMaxWidth(0.96F)
}
) {
Text(stringResource(R.string.delete_current_config))
Icon(imageVector = Icons.Default.Delete, contentDescription = stringResource(R.string.delete_current_config))
}
}
SwitchItem(

View File

@@ -418,7 +418,6 @@ private fun DeviceOwner() {
val context = LocalContext.current
val dpm = context.getDPM()
var deactivateDialog by remember { mutableStateOf(false) }
var resetPolicy by remember { mutableStateOf(true) }
val deviceOwner = context.isDeviceOwner
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) {
Spacer(Modifier.padding(vertical = 10.dp))
@@ -443,6 +442,7 @@ private fun DeviceOwner() {
}
}
if(deactivateDialog) {
var resetPolicy by remember { mutableStateOf(false) }
val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE)
val coroutine = rememberCoroutineScope()
AlertDialog(

View File

@@ -38,7 +38,6 @@ import android.app.admin.SystemUpdatePolicy.TYPE_POSTPONE
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.icu.text.IDNA
import android.net.Uri
import android.os.Build.VERSION
import android.os.UserManager
@@ -55,13 +54,15 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
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.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.List
import androidx.compose.material.icons.filled.Add
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
@@ -77,7 +78,6 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
@@ -140,8 +140,6 @@ fun SystemManage(navCtrl: NavHostController) {
val localNavCtrl = rememberNavController()
val backStackEntry by localNavCtrl.currentBackStackEntryAsState()
val scrollState = rememberScrollState()
val rebootDialog = remember { mutableStateOf(false) }
val bugReportDialog = remember { mutableStateOf(false) }
Scaffold(
topBar = {
TopBar(backStackEntry,navCtrl,localNavCtrl) {
@@ -162,7 +160,7 @@ fun SystemManage(navCtrl: NavHostController) {
popExitTransition = Animations.navHostPopExitTransition,
modifier = Modifier.padding(top = it.calculateTopPadding())
) {
composable(route = "Home") { Home(localNavCtrl, scrollState, rebootDialog, bugReportDialog) }
composable(route = "Home") { Home(localNavCtrl, scrollState) }
composable(route = "Switches") { Switches() }
composable(route = "Keyguard") { Keyguard() }
composable(route = "EditTime") { EditTime() }
@@ -180,16 +178,11 @@ fun SystemManage(navCtrl: NavHostController) {
composable(route = "FRP") { FactoryResetProtection() }
}
}
if(rebootDialog.value) {
RebootDialog(rebootDialog)
}
if(bugReportDialog.value) {
BugReportDialog(bugReportDialog)
}
}
@SuppressLint("NewApi")
@Composable
private fun Home(navCtrl: NavHostController, scrollState: ScrollState, rebootDialog: MutableState<Boolean>, bugReportDialog: MutableState<Boolean>) {
private fun Home(navCtrl: NavHostController, scrollState: ScrollState) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
@@ -198,6 +191,7 @@ private fun Home(navCtrl: NavHostController, scrollState: ScrollState, rebootDia
val dangerousFeatures = sharedPref.getBoolean("dangerous_features", false)
val deviceOwner = context.isDeviceOwner
val profileOwner = context.isProfileOwner
var dialog by remember { mutableIntStateOf(0) }
Column(modifier = Modifier.fillMaxSize().verticalScroll(scrollState)) {
Text(
text = stringResource(R.string.system_manage),
@@ -209,10 +203,10 @@ private fun Home(navCtrl: NavHostController, scrollState: ScrollState, rebootDia
}
SubPageItem(R.string.keyguard, "", R.drawable.screen_lock_portrait_fill0) { navCtrl.navigate("Keyguard") }
if(VERSION.SDK_INT >= 24 && deviceOwner) {
SubPageItem(R.string.reboot, "", R.drawable.restart_alt_fill0) { rebootDialog.value = true }
SubPageItem(R.string.reboot, "", R.drawable.restart_alt_fill0) { dialog = 1 }
}
if(deviceOwner && ((VERSION.SDK_INT >= 28 && dpm.isAffiliatedUser) || VERSION.SDK_INT >= 24)) {
SubPageItem(R.string.bug_report, "", R.drawable.bug_report_fill0) { bugReportDialog.value = true }
SubPageItem(R.string.bug_report, "", R.drawable.bug_report_fill0) { dialog = 2 }
}
if(VERSION.SDK_INT >= 28 && (deviceOwner || dpm.isOrgProfile(receiver))) {
SubPageItem(R.string.edit_time, "", R.drawable.schedule_fill0) { navCtrl.navigate("EditTime") }
@@ -254,6 +248,32 @@ private fun Home(navCtrl: NavHostController, scrollState: ScrollState, rebootDia
Spacer(Modifier.padding(vertical = 30.dp))
LaunchedEffect(Unit) { fileUriFlow.value = Uri.parse("") }
}
if(dialog != 0) AlertDialog(
onDismissRequest = { dialog = 0 },
title = { Text(stringResource(if(dialog == 1) R.string.reboot else R.string.bug_report)) },
text = { Text(stringResource(if(dialog == 1) R.string.info_reboot else R.string.confirm_bug_report)) },
dismissButton = {
TextButton(onClick = { dialog = 0 }) {
Text(stringResource(R.string.cancel))
}
},
confirmButton = {
TextButton(
onClick = {
if(dialog == 1) {
dpm.reboot(receiver)
} else {
val result = dpm.requestBugreport(receiver)
Toast.makeText(context, if(result) R.string.success else R.string.failed, Toast.LENGTH_SHORT).show()
}
dialog = 0
}
) {
Text(stringResource(R.string.confirm))
}
},
modifier = Modifier.fillMaxWidth()
)
}
@Composable
@@ -406,63 +426,6 @@ private fun Keyguard() {
}
}
@SuppressLint("NewApi")
@Composable
private fun BugReportDialog(status: MutableState<Boolean>) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
AlertDialog(
onDismissRequest = { status.value = false },
title = { Text(stringResource(R.string.bug_report)) },
text = { Text(stringResource(R.string.confirm_bug_report)) },
dismissButton = {
TextButton(onClick = { status.value = false }) {
Text(stringResource(R.string.cancel))
}
},
confirmButton = {
TextButton(
onClick = {
val result = dpm.requestBugreport(receiver)
Toast.makeText(context, if(result) R.string.success else R.string.failed, Toast.LENGTH_SHORT).show()
status.value = false
}
) {
Text(stringResource(R.string.confirm))
}
},
modifier = Modifier.fillMaxWidth()
)
}
@SuppressLint("NewApi")
@Composable
private fun RebootDialog(status: MutableState<Boolean>) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
AlertDialog(
onDismissRequest = { status.value = false },
title = { Text(stringResource(R.string.reboot)) },
text = { Text(stringResource(R.string.info_reboot)) },
dismissButton = {
TextButton(onClick = { status.value = false }) {
Text(stringResource(R.string.cancel))
}
},
confirmButton = {
TextButton(
onClick = { dpm.reboot(receiver) },
colors = ButtonDefaults.textButtonColors(contentColor = colorScheme.error)
) {
Text(stringResource(R.string.confirm))
}
},
modifier = Modifier.fillMaxWidth()
)
}
@SuppressLint("NewApi")
@Composable
private fun EditTime() {
@@ -501,8 +464,8 @@ private fun EditTimeZone() {
val dpm = context.getDPM()
val focusMgr = LocalFocusManager.current
val receiver = context.getReceiver()
var expanded by remember { mutableStateOf(false) }
var inputTimezone by remember { mutableStateOf("") }
var dialog by remember { mutableStateOf(false) }
Column(
modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally
@@ -514,6 +477,11 @@ private fun EditTimeZone() {
value = inputTimezone,
label = { Text(stringResource(R.string.timezone_id)) },
onValueChange = { inputTimezone = it },
trailingIcon = {
IconButton(onClick = { dialog = true }) {
Icon(imageVector = Icons.AutoMirrored.Default.List, contentDescription = null)
}
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Ascii, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
modifier = Modifier.fillMaxWidth()
@@ -524,27 +492,41 @@ private fun EditTimeZone() {
val result = dpm.setTimeZone(receiver, inputTimezone)
Toast.makeText(context, if(result) R.string.success else R.string.failed, Toast.LENGTH_SHORT).show()
},
modifier = Modifier.width(100.dp)
modifier = Modifier.fillMaxWidth()
) {
Text(stringResource(R.string.apply))
}
Spacer(Modifier.padding(vertical = 7.dp))
Button(onClick = { expanded = !expanded }) {
Text(stringResource(if(expanded) R.string.hide_all_timezones else R.string.view_all_timezones))
}
AnimatedVisibility(expanded) {
var ids = ""
TimeZone.getAvailableIDs().forEach { ids += "$it\n" }
SelectionContainer {
Text(ids)
}
}
Spacer(Modifier.padding(vertical = 10.dp))
Information {
Text(stringResource(R.string.disable_auto_time_zone_before_set))
}
Spacer(Modifier.padding(vertical = 30.dp))
}
if(dialog) AlertDialog(
text = {
LazyColumn {
items(TimeZone.getAvailableIDs()) {
Text(
text = it,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 1.dp)
.clip(RoundedCornerShape(15))
.clickable {
inputTimezone = it
dialog = false
}
.padding(start = 6.dp, top = 10.dp, bottom = 10.dp)
)
}
}
},
confirmButton = {
TextButton(onClick = { dialog = false }) {
Text(stringResource(R.string.cancel))
}
},
onDismissRequest = { dialog = false }
)
}
@SuppressLint("NewApi")

View File

@@ -40,16 +40,25 @@ fun SubPageItem(
operation: () -> Unit
) {
Row(
modifier = Modifier.fillMaxWidth().clickable(onClick = operation).padding(top = 15.dp, bottom = 15.dp, start = 30.dp, end = 12.dp),
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = operation)
.padding(start = 25.dp, end = 15.dp)
.padding(vertical = 12.dp + (if(desc != "") 0 else 3).dp),
verticalAlignment = Alignment.CenterVertically
) {
if(icon != null) {
Icon(painter = painterResource(icon), contentDescription = stringResource(title), modifier = Modifier.padding(top = 1.dp))
Spacer(Modifier.padding(start = 15.dp))
}
if(icon != null) Icon(
painter = painterResource(icon),
contentDescription = null,
modifier = Modifier.padding(top = 1.dp, end = 20.dp).offset(x = (-2).dp)
)
Column {
Text(text = stringResource(title), style = typography.titleLarge, modifier = Modifier.padding(bottom = if(zhCN) { 2 } else { 0 }.dp))
if(desc!="") { Text(text = desc, color = colorScheme.onBackground.copy(alpha = 0.8F)) }
Text(
text = stringResource(title),
style = typography.titleLarge,
modifier = Modifier.padding(bottom = if(zhCN) 2.dp else 0.dp)
)
if(desc != "") { Text(text = desc, color = colorScheme.onBackground.copy(alpha = 0.8F)) }
}
}
}
@@ -160,22 +169,22 @@ fun SwitchItem(
modifier = Modifier
.fillMaxWidth()
.clickable(enabled = onClickBlank != null, onClick = onClickBlank?:{})
.padding(top = 5.dp, bottom = 5.dp, start = if(padding) 25.dp else 0.dp, end = if(padding) 15.dp else 0.dp)
.padding(start = if(padding) 25.dp else 0.dp, end = if(padding) 15.dp else 0.dp, top = 5.dp, bottom = 5.dp)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.align(Alignment.CenterStart)
) {
if(icon != null) {
Icon(painter = painterResource(icon),contentDescription = null)
Spacer(Modifier.padding(start = 15.dp))
}
Column(modifier = Modifier.padding(end = 60.dp)) {
if(icon != null) Icon(
painter = painterResource(icon),
contentDescription = null,
modifier = Modifier.padding(end = 20.dp).offset(x = (-2).dp)
)
Column(modifier = Modifier.padding(end = 60.dp, bottom = if(zhCN) 2.dp else 0.dp)) {
Text(text = stringResource(title), style = typography.titleLarge)
if(desc!="") {
if(desc != "") {
Text(text = desc, color = colorScheme.onBackground.copy(alpha = 0.8F))
}
if(zhCN) { Spacer(Modifier.padding(vertical = 1.dp)) }
}
}
Switch(