Improve UI

This commit is contained in:
BinTianqi
2025-05-17 14:03:17 +08:00
parent fdcb7c179f
commit b547c8add8
9 changed files with 112 additions and 68 deletions

View File

@@ -38,10 +38,6 @@ android {
"proguard-rules.pro" "proguard-rules.pro"
) )
signingConfig = signingConfigs.getByName("defaultSignature") signingConfig = signingConfigs.getByName("defaultSignature")
composeCompiler {
includeSourceInformation = false
includeTraceMarkers = false
}
} }
debug { debug {
signingConfig = signingConfigs.getByName("defaultSignature") signingConfig = signingConfigs.getByName("defaultSignature")
@@ -64,6 +60,10 @@ android {
dependenciesInfo { dependenciesInfo {
includeInApk = false includeInApk = false
} }
composeCompiler {
includeSourceInformation = false
includeTraceMarkers = false
}
} }
kotlin { kotlin {

View File

@@ -1,6 +1,5 @@
package com.bintianqi.owndroid package com.bintianqi.owndroid
import android.annotation.SuppressLint
import android.os.Build.VERSION import android.os.Build.VERSION
import android.os.Bundle import android.os.Bundle
import android.widget.Toast import android.widget.Toast
@@ -237,13 +236,11 @@ import com.bintianqi.owndroid.ui.Animations
import com.bintianqi.owndroid.ui.theme.OwnDroidTheme import com.bintianqi.owndroid.ui.theme.OwnDroidTheme
import com.rosan.dhizuku.api.Dhizuku import com.rosan.dhizuku.api.Dhizuku
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import org.lsposed.hiddenapibypass.HiddenApiBypass import org.lsposed.hiddenapibypass.HiddenApiBypass
import java.util.Locale import java.util.Locale
val backToHomeStateFlow = MutableStateFlow(false)
@ExperimentalMaterial3Api @ExperimentalMaterial3Api
class MainActivity : FragmentActivity() { class MainActivity : FragmentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@@ -291,12 +288,7 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) {
val context = LocalContext.current val context = LocalContext.current
val receiver = context.getReceiver() val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
val backToHome by backToHomeStateFlow.collectAsState()
val lifecycleOwner = LocalLifecycleOwner.current val lifecycleOwner = LocalLifecycleOwner.current
LaunchedEffect(backToHome) {
if(backToHome) { navController.navigateUp(); backToHomeStateFlow.value = false }
}
val userRestrictions by vm.userRestrictions.collectAsStateWithLifecycle()
fun navigateUp() { navController.navigateUp() } fun navigateUp() { navController.navigateUp() }
fun navigate(destination: Any) { navController.navigate(destination) } fun navigate(destination: Any) { navController.navigate(destination) }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
@@ -320,7 +312,7 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) {
popEnterTransition = Animations.navHostPopEnterTransition, popEnterTransition = Animations.navHostPopEnterTransition,
popExitTransition = Animations.navHostPopExitTransition popExitTransition = Animations.navHostPopExitTransition
) { ) {
composable<Home> { HomeScreen { navController.navigate(it) } } composable<Home> { HomeScreen(::navigate) }
composable<WorkModes> { composable<WorkModes> {
WorkModesScreen(it.toRoute(), ::navigateUp, { WorkModesScreen(it.toRoute(), ::navigateUp, {
navController.navigate(Home) { navController.navigate(Home) {
@@ -330,9 +322,7 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) {
navController.navigate(WorkModes(false)) { navController.navigate(WorkModes(false)) {
popUpTo<Home> { inclusive = true } popUpTo<Home> { inclusive = true }
} }
}, { }, ::navigate)
navController.navigate(it)
})
} }
composable<DelegatedAdmins> { DelegatedAdminsScreen(::navigateUp, ::navigate) } composable<DelegatedAdmins> { DelegatedAdminsScreen(::navigateUp, ::navigate) }
@@ -369,14 +359,14 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) {
composable<WipeData> { WipeDataScreen(::navigateUp) } composable<WipeData> { WipeDataScreen(::navigateUp) }
composable<Network> { NetworkScreen(::navigateUp, ::navigate) } composable<Network> { NetworkScreen(::navigateUp, ::navigate) }
composable<WiFi> { WifiScreen(::navigateUp, { navController.navigate(it) }) { navController.navigate(AddNetwork, it)} } composable<WiFi> { WifiScreen(::navigateUp, ::navigate) { navController.navigate(AddNetwork, it)} }
composable<NetworkOptions> { NetworkOptionsScreen(::navigateUp) } composable<NetworkOptions> { NetworkOptionsScreen(::navigateUp) }
composable<AddNetwork> { AddNetworkScreen(it.arguments!!, ::navigateUp) } composable<AddNetwork> { AddNetworkScreen(it.arguments!!, ::navigateUp) }
composable<WifiSecurityLevel> { WifiSecurityLevelScreen(::navigateUp) } composable<WifiSecurityLevel> { WifiSecurityLevelScreen(::navigateUp) }
composable<WifiSsidPolicyScreen> { WifiSsidPolicyScreen(::navigateUp) } composable<WifiSsidPolicyScreen> { WifiSsidPolicyScreen(::navigateUp) }
composable<QueryNetworkStats> { NetworkStatsScreen(::navigateUp, ::navigate) } composable<QueryNetworkStats> { NetworkStatsScreen(::navigateUp, ::navigate) }
composable<NetworkStatsViewer>(mapOf(serializableNavTypePair<List<NetworkStatsViewer.Data>>())) { composable<NetworkStatsViewer>(mapOf(serializableNavTypePair<List<NetworkStatsViewer.Data>>())) {
NetworkStatsViewerScreen(it.toRoute()) { navController.navigateUp() } NetworkStatsViewerScreen(it.toRoute(), ::navigateUp)
} }
composable<PrivateDns> { PrivateDnsScreen(::navigateUp) } composable<PrivateDns> { PrivateDnsScreen(::navigateUp) }
composable<AlwaysOnVpnPackage> { AlwaysOnVpnPackageScreen(::navigateUp) } composable<AlwaysOnVpnPackage> { AlwaysOnVpnPackageScreen(::navigateUp) }
@@ -433,25 +423,12 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) {
composable<SetDefaultDialer> { SetDefaultDialerScreen(::navigateUp) } composable<SetDefaultDialer> { SetDefaultDialerScreen(::navigateUp) }
composable<UserRestriction> { composable<UserRestriction> {
LaunchedEffect(Unit) {
vm.userRestrictions.value = context.getDPM().getUserRestrictions(receiver)
}
UserRestrictionScreen(::navigateUp) { title, items -> UserRestrictionScreen(::navigateUp) { title, items ->
navController.navigate(UserRestrictionOptions(title, items)) navigate(UserRestrictionOptions(title, items))
} }
} }
composable<UserRestrictionOptions>(mapOf(serializableNavTypePair<List<Restriction>>())) { composable<UserRestrictionOptions>(mapOf(serializableNavTypePair<List<Restriction>>())) {
UserRestrictionOptionsScreen(it.toRoute(), userRestrictions, ::navigateUp) { id, status -> UserRestrictionOptionsScreen(it.toRoute(), ::navigateUp)
try {
val dpm = context.getDPM()
if(status) dpm.addUserRestriction(receiver, id)
else dpm.clearUserRestriction(receiver, id)
@SuppressLint("NewApi")
vm.userRestrictions.value = dpm.getUserRestrictions(receiver)
} catch(_: Exception) {
context.showOperationResultToast(false)
}
}
} }
composable<Users> { UsersScreen(::navigateUp, ::navigate) } composable<Users> { UsersScreen(::navigateUp, ::navigate) }

View File

@@ -1,7 +1,6 @@
package com.bintianqi.owndroid package com.bintianqi.owndroid
import android.app.Application import android.app.Application
import android.os.Bundle
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@@ -9,7 +8,6 @@ import kotlinx.coroutines.launch
class MyViewModel(application: Application): AndroidViewModel(application) { class MyViewModel(application: Application): AndroidViewModel(application) {
val theme = MutableStateFlow(ThemeSettings()) val theme = MutableStateFlow(ThemeSettings())
val userRestrictions = MutableStateFlow(Bundle())
init { init {
val sp = SharedPrefs(application) val sp = SharedPrefs(application)

View File

@@ -12,20 +12,29 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FilledTonalButton import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.LargeTopAppBar
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Switch import androidx.compose.material3.Switch
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -35,6 +44,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
@@ -49,6 +59,7 @@ import androidx.core.net.toUri
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bintianqi.owndroid.ui.FunctionItem import com.bintianqi.owndroid.ui.FunctionItem
import com.bintianqi.owndroid.ui.MyScaffold import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.NavIcon
import com.bintianqi.owndroid.ui.Notes import com.bintianqi.owndroid.ui.Notes
import com.bintianqi.owndroid.ui.SwitchItem import com.bintianqi.owndroid.ui.SwitchItem
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@@ -59,6 +70,7 @@ import java.util.Locale
@Serializable object Settings @Serializable object Settings
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun SettingsScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) { fun SettingsScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
val context = LocalContext.current val context = LocalContext.current
@@ -66,7 +78,46 @@ fun SettingsScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
val exportLogsLauncher = rememberLauncherForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) { val exportLogsLauncher = rememberLauncherForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) {
if(it != null) exportLogs(context, it) if(it != null) exportLogs(context, it)
} }
MyScaffold(R.string.settings, onNavigateUp, 0.dp) { val sb = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
var dropdown by remember { mutableStateOf(false) }
Scaffold(
Modifier.nestedScroll(sb.nestedScrollConnection),
topBar = {
LargeTopAppBar(
{ Text(stringResource(R.string.settings)) },
navigationIcon = { NavIcon(onNavigateUp) },
scrollBehavior = sb,
actions = {
Box {
IconButton({ dropdown = true }) {
Icon(Icons.Default.MoreVert, null)
}
DropdownMenu(dropdown, { dropdown = false }) {
DropdownMenuItem(
{ Text(stringResource(R.string.export_logs)) },
{
dropdown = false
val time = SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault())
.format(Date(System.currentTimeMillis()))
exportLogsLauncher.launch("owndroid_log_$time")
},
leadingIcon = {
Icon(painterResource(R.drawable.description_fill0), null)
}
)
}
}
}
)
}
) { paddingValues ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
.verticalScroll(rememberScrollState())
.padding(bottom = 80.dp)
) {
FunctionItem(title = R.string.options, icon = R.drawable.tune_fill0) { onNavigate(SettingsOptions) } FunctionItem(title = R.string.options, icon = R.drawable.tune_fill0) { onNavigate(SettingsOptions) }
FunctionItem(title = R.string.appearance, icon = R.drawable.format_paint_fill0) { onNavigate(Appearance) } FunctionItem(title = R.string.appearance, icon = R.drawable.format_paint_fill0) { onNavigate(Appearance) }
FunctionItem(R.string.app_lock, icon = R.drawable.lock_fill0) { onNavigate(AppLockSettings) } FunctionItem(R.string.app_lock, icon = R.drawable.lock_fill0) { onNavigate(AppLockSettings) }
@@ -74,12 +125,9 @@ fun SettingsScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
FunctionItem(title = R.string.api, icon = R.drawable.code_fill0) { onNavigate(ApiSettings) } FunctionItem(title = R.string.api, icon = R.drawable.code_fill0) { onNavigate(ApiSettings) }
if (privilege.device && !privilege.dhizuku) if (privilege.device && !privilege.dhizuku)
FunctionItem(R.string.notifications, icon = R.drawable.notifications_fill0) { onNavigate(Notifications) } FunctionItem(R.string.notifications, icon = R.drawable.notifications_fill0) { onNavigate(Notifications) }
FunctionItem(title = R.string.export_logs, icon = R.drawable.description_fill0) {
val time = SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()).format(Date(System.currentTimeMillis()))
exportLogsLauncher.launch("owndroid_log_$time")
}
FunctionItem(title = R.string.about, icon = R.drawable.info_fill0) { onNavigate(About) } FunctionItem(title = R.string.about, icon = R.drawable.info_fill0) { onNavigate(About) }
} }
}
} }
@Serializable object SettingsOptions @Serializable object SettingsOptions
@@ -111,6 +159,10 @@ fun SettingsOptionsScreen(onNavigateUp: () -> Unit) {
fun AppearanceScreen(onNavigateUp: () -> Unit, currentTheme: ThemeSettings, onThemeChange: (ThemeSettings) -> Unit) { fun AppearanceScreen(onNavigateUp: () -> Unit, currentTheme: ThemeSettings, onThemeChange: (ThemeSettings) -> Unit) {
var darkThemeMenu by remember { mutableStateOf(false) } var darkThemeMenu by remember { mutableStateOf(false) }
var theme by remember { mutableStateOf(currentTheme) } var theme by remember { mutableStateOf(currentTheme) }
fun update(it: ThemeSettings) {
theme = it
onThemeChange(it)
}
val darkThemeTextID = when(theme.darkTheme) { val darkThemeTextID = when(theme.darkTheme) {
1 -> R.string.on 1 -> R.string.on
0 -> R.string.off 0 -> R.string.off
@@ -121,7 +173,7 @@ fun AppearanceScreen(onNavigateUp: () -> Unit, currentTheme: ThemeSettings, onTh
SwitchItem( SwitchItem(
R.string.material_you_color, R.string.material_you_color,
state = theme.materialYou, state = theme.materialYou,
onCheckedChange = { theme = theme.copy(materialYou = it) } onCheckedChange = { update(theme.copy(materialYou = it)) }
) )
} }
Box { Box {
@@ -133,13 +185,14 @@ fun AppearanceScreen(onNavigateUp: () -> Unit, currentTheme: ThemeSettings, onTh
DropdownMenuItem( DropdownMenuItem(
text = { Text(stringResource(R.string.follow_system)) }, text = { Text(stringResource(R.string.follow_system)) },
onClick = { onClick = {
theme = theme.copy(darkTheme = -1) update(theme.copy(darkTheme = -1))
darkThemeMenu = false darkThemeMenu = false
} }
) )
DropdownMenuItem( DropdownMenuItem(
text = { Text(stringResource(R.string.on)) }, text = { Text(stringResource(R.string.on)) },
onClick = { onClick = {
update(theme.copy(darkTheme = 1))
theme = theme.copy(darkTheme = 1) theme = theme.copy(darkTheme = 1)
darkThemeMenu = false darkThemeMenu = false
} }
@@ -147,19 +200,17 @@ fun AppearanceScreen(onNavigateUp: () -> Unit, currentTheme: ThemeSettings, onTh
DropdownMenuItem( DropdownMenuItem(
text = { Text(stringResource(R.string.off)) }, text = { Text(stringResource(R.string.off)) },
onClick = { onClick = {
theme = theme.copy(darkTheme = 0) update(theme.copy(darkTheme = 0))
darkThemeMenu = false darkThemeMenu = false
} }
) )
} }
} }
AnimatedVisibility(theme.darkTheme == 1 || (theme.darkTheme == -1 && isSystemInDarkTheme())) { AnimatedVisibility(theme.darkTheme == 1 || (theme.darkTheme == -1 && isSystemInDarkTheme())) {
SwitchItem(R.string.black_theme, state = theme.blackTheme, onCheckedChange = { theme = theme.copy(blackTheme = it) }) SwitchItem(
} R.string.black_theme, state = theme.blackTheme,
AnimatedVisibility(theme != currentTheme, Modifier.fillMaxWidth().padding(8.dp)) { onCheckedChange = { update(theme.copy(blackTheme = it)) }
Button({onThemeChange(theme)}) { )
Text(stringResource(R.string.apply))
}
} }
} }
} }

View File

@@ -32,7 +32,6 @@ import com.bintianqi.owndroid.backToHomeStateFlow
import com.bintianqi.owndroid.createShortcuts import com.bintianqi.owndroid.createShortcuts
import com.bintianqi.owndroid.myPrivilege import com.bintianqi.owndroid.myPrivilege
import com.rosan.dhizuku.api.Dhizuku import com.rosan.dhizuku.api.Dhizuku
import com.rosan.dhizuku.api.Dhizuku.binderWrapper
import com.rosan.dhizuku.api.DhizukuBinderWrapper import com.rosan.dhizuku.api.DhizukuBinderWrapper
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
@@ -73,7 +72,7 @@ fun binderWrapperDevicePolicyManager(appContext: Context): DevicePolicyManager?
val oldInterface = field[manager] as IDevicePolicyManager val oldInterface = field[manager] as IDevicePolicyManager
if (oldInterface is DhizukuBinderWrapper) return manager if (oldInterface is DhizukuBinderWrapper) return manager
val oldBinder = oldInterface.asBinder() val oldBinder = oldInterface.asBinder()
val newBinder = binderWrapper(oldBinder) val newBinder = Dhizuku.binderWrapper(oldBinder)
val newInterface = IDevicePolicyManager.Stub.asInterface(newBinder) val newInterface = IDevicePolicyManager.Stub.asInterface(newBinder)
field[manager] = newInterface field[manager] = newInterface
return manager return manager
@@ -93,7 +92,7 @@ private fun binderWrapperPackageInstaller(appContext: Context): PackageInstaller
val oldInterface = field[installer] as IPackageInstaller val oldInterface = field[installer] as IPackageInstaller
if (oldInterface is DhizukuBinderWrapper) return installer if (oldInterface is DhizukuBinderWrapper) return installer
val oldBinder = oldInterface.asBinder() val oldBinder = oldInterface.asBinder()
val newBinder = binderWrapper(oldBinder) val newBinder = Dhizuku.binderWrapper(oldBinder)
val newInterface = IPackageInstaller.Stub.asInterface(newBinder) val newInterface = IPackageInstaller.Stub.asInterface(newBinder)
field[installer] = newInterface field[installer] = newInterface
return installer return installer
@@ -107,7 +106,6 @@ fun Context.getPackageInstaller(): PackageInstaller {
if(SharedPrefs(this).dhizuku) { if(SharedPrefs(this).dhizuku) {
if (!dhizukuPermissionGranted()) { if (!dhizukuPermissionGranted()) {
dhizukuErrorStatus.value = 2 dhizukuErrorStatus.value = 2
backToHomeStateFlow.value = true
return this.packageManager.packageInstaller return this.packageManager.packageInstaller
} }
return binderWrapperPackageInstaller(this) ?: this.packageManager.packageInstaller return binderWrapperPackageInstaller(this) ?: this.packageManager.packageInstaller
@@ -120,7 +118,6 @@ fun Context.getDPM(): DevicePolicyManager {
if(SharedPrefs(this).dhizuku) { if(SharedPrefs(this).dhizuku) {
if (!dhizukuPermissionGranted()) { if (!dhizukuPermissionGranted()) {
dhizukuErrorStatus.value = 2 dhizukuErrorStatus.value = 2
backToHomeStateFlow.value = true
return this.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager return this.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
} }
return binderWrapperDevicePolicyManager(this) ?: this.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager return binderWrapperDevicePolicyManager(this) ?: this.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager

View File

@@ -295,7 +295,7 @@ fun WorkModesScreen(
Spacer(Modifier.padding(horizontal = 2.dp)) Spacer(Modifier.padding(horizontal = 2.dp))
Button({ dialog = 5 }) { Text(stringResource(R.string.adb_command)) } Button({ dialog = 5 }) { Text(stringResource(R.string.adb_command)) }
Spacer(Modifier.padding(horizontal = 2.dp)) Spacer(Modifier.padding(horizontal = 2.dp))
if (VERSION.SDK_INT == 35) Button({ if (VERSION.SDK_INT >= 33) Button({
dialog = 6 dialog = 6
}) { }) {
Text(stringResource(R.string.root_force_activate)) Text(stringResource(R.string.root_force_activate))
@@ -575,6 +575,7 @@ fun LockScreenInfoScreen(onNavigateUp: () -> Unit) {
onClick = { onClick = {
focusMgr.clearFocus() focusMgr.clearFocus()
dpm.setDeviceOwnerLockScreenInfo(receiver, null) dpm.setDeviceOwnerLockScreenInfo(receiver, null)
infoText = ""
context.showOperationResultToast(true) context.showOperationResultToast(true)
}, },
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()

View File

@@ -10,8 +10,12 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -73,14 +77,30 @@ data class UserRestrictionOptions(
@RequiresApi(24) @RequiresApi(24)
@Composable @Composable
fun UserRestrictionOptionsScreen( fun UserRestrictionOptionsScreen(
data: UserRestrictionOptions, restrictions: Bundle, data: UserRestrictionOptions, onNavigateUp: () -> Unit
onNavigateUp: () -> Unit, onRestrictionChange: (String, Boolean) -> Unit
) { ) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val status = remember { mutableStateMapOf<String, Boolean>() }
LaunchedEffect(Unit) {
val restrictions = dpm.getUserRestrictions(receiver)
data.items.forEach {
status.put(it.id, restrictions.getBoolean(it.id))
}
}
MyScaffold(data.title, onNavigateUp, 0.dp) { MyScaffold(data.title, onNavigateUp, 0.dp) {
data.items.filter { Build.VERSION.SDK_INT >= it.requiresApi }.forEach { restriction -> data.items.filter { Build.VERSION.SDK_INT >= it.requiresApi }.forEach { restriction ->
SwitchItem( SwitchItem(
restriction.name, restriction.id, restriction.icon, restriction.name, restriction.id, restriction.icon, status[restriction.id] == true,
restrictions.getBoolean(restriction.id), { onRestrictionChange(restriction.id, it) }, padding = true {
if (it) {
dpm.addUserRestriction(receiver, restriction.id)
} else {
dpm.clearUserRestriction(receiver, restriction.id)
}
status[restriction.id] = dpm.getUserRestrictions(receiver).getBoolean(restriction.id)
}, padding = true
) )
} }
} }

View File

@@ -102,7 +102,7 @@ fun OwnDroidTheme(
darkTheme -> darkScheme darkTheme -> darkScheme
else -> lightScheme else -> lightScheme
}.let { }.let {
if(darkTheme && theme.blackTheme) it.copy(background = Color.Black) else it if(darkTheme && theme.blackTheme) it.copy(background = Color.Black, surface = Color.Black) else it
} }
val view = LocalView.current val view = LocalView.current
SideEffect { SideEffect {

View File

@@ -1,5 +1,5 @@
[versions] [versions]
agp = "8.9.2" agp = "8.10.0"
kotlin = "2.1.20" kotlin = "2.1.20"
navigation-compose = "2.9.0" navigation-compose = "2.9.0"