From c408e3b8ced9c1cb84c696ff5ce99e9c062c7750 Mon Sep 17 00:00:00 2001 From: BinTianqi Date: Sat, 23 Nov 2024 19:47:47 +0800 Subject: [PATCH] Timezone ID selector Use IconButton to save/delete preferential network config Fix horizontal padding across SubPageItem and SwitchItem Delete User guide link in About --- .../com/bintianqi/owndroid/MainActivity.kt | 4 +- .../java/com/bintianqi/owndroid/Setting.kt | 3 +- .../com/bintianqi/owndroid/dpm/Network.kt | 21 +-- .../com/bintianqi/owndroid/dpm/Permissions.kt | 2 +- .../bintianqi/owndroid/dpm/SystemManager.kt | 154 ++++++++---------- .../com/bintianqi/owndroid/ui/Components.kt | 39 +++-- app/src/main/res/drawable/save_fill0.xml | 9 + app/src/main/res/values-ru/strings.xml | 3 - app/src/main/res/values-tr/strings.xml | 3 - app/src/main/res/values-zh-rCN/strings.xml | 3 - app/src/main/res/values/strings.xml | 3 - 11 files changed, 115 insertions(+), 129 deletions(-) create mode 100644 app/src/main/res/drawable/save_fill0.xml diff --git a/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt b/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt index 3f55b97..834ca64 100644 --- a/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt +++ b/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt @@ -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() diff --git a/app/src/main/java/com/bintianqi/owndroid/Setting.kt b/app/src/main/java/com/bintianqi/owndroid/Setting.kt index cea4b10..60113dc 100644 --- a/app/src/main/java/com/bintianqi/owndroid/Setting.kt +++ b/app/src/main/java/com/bintianqi/owndroid/Setting.kt @@ -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") } } } diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/Network.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/Network.kt index 44995ba..6e8c36a 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Network.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/Network.kt @@ -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( diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt index d47ed2e..da68326 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt @@ -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( diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/SystemManager.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/SystemManager.kt index fe6fbde..445e85f 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/SystemManager.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/SystemManager.kt @@ -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, bugReportDialog: MutableState) { +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) { - 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) { - 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") diff --git a/app/src/main/java/com/bintianqi/owndroid/ui/Components.kt b/app/src/main/java/com/bintianqi/owndroid/ui/Components.kt index b1cb904..5a7385a 100644 --- a/app/src/main/java/com/bintianqi/owndroid/ui/Components.kt +++ b/app/src/main/java/com/bintianqi/owndroid/ui/Components.kt @@ -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( diff --git a/app/src/main/res/drawable/save_fill0.xml b/app/src/main/res/drawable/save_fill0.xml new file mode 100644 index 0000000..1f604df --- /dev/null +++ b/app/src/main/res/drawable/save_fill0.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 09afc35..d37e435 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -143,8 +143,6 @@ Перезагрузить Изменить время Изменить часовой пояс - Посмотреть все идентификаторы часовых поясов - Скрыть все идентификаторы часовых поясов Идентификатор часового пояса Автоматический часовой пояс должен быть отключен перед установкой пользовательского часового пояса. Политика разрешений @@ -546,7 +544,6 @@ Follow system Black theme О приложении - Руководство пользователя Исходный код Тема diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index ec616f2..872b062 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -144,8 +144,6 @@ Yeniden başlat Zamanı düzenle Saat dilimini düzenle - Tüm saat dilimi kimliklerini görüntüle - Tüm saat dilimi kimliklerini gizle Saat dilimi kimliği Özel bir saat dilimi ayarlamadan önce otomatik saat dilimi devre dışı bırakılmalıdır İzin politikası @@ -541,7 +539,6 @@ Follow system Black theme Hakkında - Kullanıcı rehberi Kaynak kodu Tema diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index dc26823..7fbbc7c 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -139,8 +139,6 @@ 重启 修改时间 修改时区 - 显示所有时区ID - 隐藏所有时区ID 时区ID 在设置时区前需要关闭自动时区 权限策略 @@ -533,7 +531,6 @@ 跟随系统 黑色主题 关于 - 使用教程 源代码 主题 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3e74045..e9a77f6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -149,8 +149,6 @@ Reboot Edit time Edit timezone - View all timezones IDs - Hide all timezones IDs Timezone ID Auto timezone should be disabled before set a custom timezone. Permission policy @@ -547,7 +545,6 @@ Follow system Black theme About - User guide Source code Theme