This commit is contained in:
BinTianqi
2025-10-16 17:45:01 +08:00
parent 9c796690e3
commit b5218d7ee5
20 changed files with 377 additions and 347 deletions

View File

@@ -25,7 +25,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@@ -44,8 +44,8 @@ import androidx.compose.ui.window.DialogProperties
fun AppLockDialog(onSucceed: () -> Unit, onDismiss: () -> Unit) = Dialog(onDismiss, DialogProperties(true, false)) { fun AppLockDialog(onSucceed: () -> Unit, onDismiss: () -> Unit) = Dialog(onDismiss, DialogProperties(true, false)) {
val context = LocalContext.current val context = LocalContext.current
val fm = LocalFocusManager.current val fm = LocalFocusManager.current
var input by remember { mutableStateOf("") } var input by rememberSaveable { mutableStateOf("") }
var isError by remember { mutableStateOf(false) } var isError by rememberSaveable { mutableStateOf(false) }
fun unlock() { fun unlock() {
if(input.hash() == SP.lockPasswordHash) { if(input.hash() == SP.lockPasswordHash) {
fm.clearFocus() fm.clearFocus()

View File

@@ -19,6 +19,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@@ -103,7 +104,7 @@ class DhizukuActivity : ComponentActivity() {
enableEdgeToEdge() enableEdgeToEdge()
val theme = ThemeSettings(SP.materialYou, SP.darkTheme, SP.blackTheme) val theme = ThemeSettings(SP.materialYou, SP.darkTheme, SP.blackTheme)
setContent { setContent {
var appLockDialog by remember { mutableStateOf(false) } var appLockDialog by rememberSaveable { mutableStateOf(false) }
OwnDroidTheme(theme) { OwnDroidTheme(theme) {
if (!appLockDialog) AlertDialog( if (!appLockDialog) AlertDialog(
icon = { icon = {

View File

@@ -14,10 +14,9 @@ import androidx.compose.foundation.gestures.detectTapGestures
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.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.ime import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
@@ -400,7 +399,7 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) {
InstallSystemUpdateScreen(vm::installSystemUpdate, ::navigateUp) InstallSystemUpdateScreen(vm::installSystemUpdate, ::navigateUp)
} }
composable<FrpPolicy> { composable<FrpPolicy> {
FrpPolicyScreen(vm::getFrpPolicy, vm::setFrpPolicy, ::navigateUp) FrpPolicyScreen(vm.getFrpPolicy(), vm::setFrpPolicy, ::navigateUp)
} }
composable<WipeData> { WipeDataScreen(vm::wipeData, ::navigateUp) } composable<WipeData> { WipeDataScreen(vm::wipeData, ::navigateUp) }
@@ -641,13 +640,14 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) {
AppearanceScreen(::navigateUp, vm.theme, vm::changeTheme) AppearanceScreen(::navigateUp, vm.theme, vm::changeTheme)
} }
composable<AppLockSettings> { composable<AppLockSettings> {
AppLockSettingsScreen(vm::getAppLockConfig, vm::setAppLockConfig, ::navigateUp) AppLockSettingsScreen(vm.getAppLockConfig(), vm::setAppLockConfig, ::navigateUp)
} }
composable<ApiSettings> { composable<ApiSettings> {
ApiSettings(vm::getApiEnabled, vm::setApiKey, ::navigateUp) ApiSettings(vm::getApiEnabled, vm::setApiKey, ::navigateUp)
} }
composable<Notifications> { composable<Notifications> {
NotificationsScreen(vm::getEnabledNotifications, vm::setNotificationEnabled, ::navigateUp) NotificationsScreen(vm.enabledNotifications, vm::getEnabledNotifications,
vm::setNotificationEnabled, ::navigateUp)
} }
composable<About> { AboutScreen(::navigateUp) } composable<About> { AboutScreen(::navigateUp) }
} }
@@ -702,7 +702,7 @@ private fun HomeScreen(onNavigate: (Any) -> Unit) {
scrollBehavior = sb scrollBehavior = sb
) )
}, },
contentWindowInsets = WindowInsets.ime contentWindowInsets = adaptiveInsets()
) { ) {
Column(Modifier Column(Modifier
.fillMaxSize() .fillMaxSize()
@@ -727,7 +727,7 @@ private fun HomeScreen(onNavigate: (Any) -> Unit) {
HomePageItem(R.string.users,R.drawable.manage_accounts_fill0) { onNavigate(Users) } HomePageItem(R.string.users,R.drawable.manage_accounts_fill0) { onNavigate(Users) }
HomePageItem(R.string.password_and_keyguard, R.drawable.password_fill0) { onNavigate(Password) } HomePageItem(R.string.password_and_keyguard, R.drawable.password_fill0) { onNavigate(Password) }
} }
Spacer(Modifier.padding(vertical = 20.dp)) Spacer(Modifier.height(BottomPadding))
} }
} }
} }

View File

@@ -163,21 +163,16 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
fun setApiKey(key: String) { fun setApiKey(key: String) {
SP.apiKeyHash = if (key.isEmpty()) "" else key.hash() SP.apiKeyHash = if (key.isEmpty()) "" else key.hash()
} }
fun getEnabledNotifications(): List<NotificationType> { val enabledNotifications = MutableStateFlow(emptyList<Int>())
fun getEnabledNotifications() {
val list = SP.notifications?.split(',')?.mapNotNull { it.toIntOrNull() } val list = SP.notifications?.split(',')?.mapNotNull { it.toIntOrNull() }
return if (list == null) { enabledNotifications.value = list ?: NotificationType.entries.map { it.id }
NotificationType.entries
} else {
NotificationType.entries.filter { it.id in list }
}
} }
fun setNotificationEnabled(type: NotificationType, enabled: Boolean) { fun setNotificationEnabled(type: NotificationType, enabled: Boolean) {
val list = SP.notifications?.split(',')?.mapNotNull { it.toIntOrNull() } enabledNotifications.update { list ->
SP.notifications = if (list == null) { if (enabled) list.plus(type.id) else list.minus(type.id)
NotificationType.entries.minus(type).map { it.id } }
} else { SP.notifications = enabledNotifications.value.joinToString(",") { it.toString() }
list.run { if (enabled) plus(type.id) else minus(type.id) }
}.joinToString { it.toString() }
} }
val chosenPackage = Channel<String>(1, BufferOverflow.DROP_LATEST) val chosenPackage = Channel<String>(1, BufferOverflow.DROP_LATEST)
@@ -267,7 +262,7 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
fun getPackagePermissions(name: String) { fun getPackagePermissions(name: String) {
if (name.isValidPackageName) { if (name.isValidPackageName) {
packagePermissions.value = runtimePermissions.associate { packagePermissions.value = runtimePermissions.associate {
it.permission to DPM.getPermissionGrantState(DAR, name, it.permission) it.id to DPM.getPermissionGrantState(DAR, name, it.id)
} }
} else { } else {
packagePermissions.value = emptyMap() packagePermissions.value = emptyMap()
@@ -1027,7 +1022,8 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
} else { } else {
Dhizuku.requestPermission(object : DhizukuRequestPermissionListener() { Dhizuku.requestPermission(object : DhizukuRequestPermissionListener() {
override fun onRequestPermission(grantResult: Int) { override fun onRequestPermission(grantResult: Int) {
if(grantResult == PackageManager.PERMISSION_GRANTED) onSucceed() if (grantResult == PackageManager.PERMISSION_GRANTED) onSucceed()
else callback(false, application.getString(R.string.dhizuku_permission_not_granted))
} }
}) })
} }

View File

@@ -16,9 +16,9 @@ object NotificationUtils {
NotificationManagerCompat.from(context).createNotificationChannelsCompat(channels) NotificationManagerCompat.from(context).createNotificationChannelsCompat(channels)
} }
fun sendBasicNotification( fun sendBasicNotification(
context: Context, type: NotificationType, channel: MyNotificationChannel, text: String context: Context, type: NotificationType, text: String
) { ) {
val notification = NotificationCompat.Builder(context, channel.id) val notification = NotificationCompat.Builder(context, type.channel.id)
.setSmallIcon(type.icon) .setSmallIcon(type.icon)
.setContentTitle(context.getString(type.text)) .setContentTitle(context.getString(type.text))
.setContentText(text) .setContentText(text)
@@ -29,7 +29,7 @@ object NotificationUtils {
fun notifyEvent(context: Context, type: NotificationType, text: String) { fun notifyEvent(context: Context, type: NotificationType, text: String) {
val enabledNotifications = SP.notifications?.split(',')?.mapNotNull { it.toIntOrNull() } val enabledNotifications = SP.notifications?.split(',')?.mapNotNull { it.toIntOrNull() }
if (enabledNotifications == null || type.id in enabledNotifications) { if (enabledNotifications == null || type.id in enabledNotifications) {
sendBasicNotification(context, type, MyNotificationChannel.Events, text) sendBasicNotification(context, type, text)
} }
} }
fun cancel(context: Context, type: NotificationType) { fun cancel(context: Context, type: NotificationType) {
@@ -38,19 +38,40 @@ object NotificationUtils {
} }
} }
enum class NotificationType(val id: Int, val text: Int, val icon: Int) { enum class NotificationType(
LockTaskMode(1, R.string.lock_task_mode, R.drawable.lock_fill0), val id: Int, val text: Int, val icon: Int, val channel: MyNotificationChannel
PasswordChanged(2, R.string.password_changed, R.drawable.password_fill0), ) {
UserAdded(3, R.string.user_added, R.drawable.person_add_fill0), LockTaskMode(
UserStarted(4, R.string.user_started, R.drawable.person_fill0), 1, R.string.lock_task_mode, R.drawable.lock_fill0, MyNotificationChannel.LockTaskMode
UserSwitched(5, R.string.user_switched, R.drawable.person_fill0), ),
UserStopped(6, R.string.user_stopped, R.drawable.person_off), PasswordChanged(
UserRemoved(7, R.string.user_removed, R.drawable.person_remove_fill0), 2, R.string.password_changed, R.drawable.password_fill0, MyNotificationChannel.Events
BugReportShared(8, R.string.bug_report_shared, R.drawable.bug_report_fill0), ),
BugReportSharingDeclined(9, R.string.bug_report_sharing_declined, R.drawable.bug_report_fill0), UserAdded(3, R.string.user_added, R.drawable.person_add_fill0, MyNotificationChannel.Events),
BugReportFailed(10, R.string.bug_report_failed, R.drawable.bug_report_fill0), UserStarted(4, R.string.user_started, R.drawable.person_fill0, MyNotificationChannel.Events),
SystemUpdatePending(11, R.string.system_update_pending, R.drawable.system_update_fill0), UserSwitched(5, R.string.user_switched, R.drawable.person_fill0, MyNotificationChannel.Events),
SecurityLogsCollected(12, R.string.security_logs_collected, R.drawable.description_fill0), UserStopped(6, R.string.user_stopped, R.drawable.person_off, MyNotificationChannel.Events),
UserRemoved(
7, R.string.user_removed, R.drawable.person_remove_fill0, MyNotificationChannel.Events
),
BugReportShared(
8, R.string.bug_report_shared, R.drawable.bug_report_fill0, MyNotificationChannel.Events
),
BugReportSharingDeclined(
9, R.string.bug_report_sharing_declined, R.drawable.bug_report_fill0,
MyNotificationChannel.Events
),
BugReportFailed(
10, R.string.bug_report_failed, R.drawable.bug_report_fill0, MyNotificationChannel.Events
),
SystemUpdatePending(
11, R.string.system_update_pending, R.drawable.system_update_fill0,
MyNotificationChannel.Events
),
SecurityLogsCollected(
12, R.string.security_logs_collected, R.drawable.description_fill0,
MyNotificationChannel.SecurityLogging
),
} }
enum class MyNotificationChannel(val id: String, val text: Int, val importance: Int) { enum class MyNotificationChannel(val id: String, val text: Int, val importance: Int) {

View File

@@ -10,10 +10,9 @@ import androidx.compose.foundation.clickable
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.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.ime import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
@@ -146,7 +145,7 @@ fun AppChooserScreen(
colors = TopAppBarDefaults.topAppBarColors(MaterialTheme.colorScheme.surfaceContainer) colors = TopAppBarDefaults.topAppBarColors(MaterialTheme.colorScheme.surfaceContainer)
) )
}, },
contentWindowInsets = WindowInsets.ime contentWindowInsets = adaptiveInsets()
) { paddingValues -> ) { paddingValues ->
LazyColumn(Modifier.fillMaxSize().padding(paddingValues)) { LazyColumn(Modifier.fillMaxSize().padding(paddingValues)) {
if (progress < 1F) stickyHeader { if (progress < 1F) stickyHeader {
@@ -174,7 +173,7 @@ fun AppChooserScreen(
} }
} }
} }
item { Spacer(Modifier.padding(vertical = 30.dp)) } item { Spacer(Modifier.height(60.dp)) }
} }
} }
} }

View File

@@ -12,10 +12,8 @@ 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.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.ime
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
@@ -39,9 +37,9 @@ import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@@ -115,7 +113,7 @@ fun SettingsScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
} }
) )
}, },
contentWindowInsets = WindowInsets.ime contentWindowInsets = adaptiveInsets()
) { paddingValues -> ) { paddingValues ->
Column( Column(
modifier = Modifier modifier = Modifier
@@ -231,22 +229,15 @@ data class AppLockConfig(
@Composable @Composable
fun AppLockSettingsScreen( fun AppLockSettingsScreen(
getConfig: () -> AppLockConfig, setConfig: (AppLockConfig) -> Unit, config: AppLockConfig, setConfig: (AppLockConfig) -> Unit,
onNavigateUp: () -> Unit onNavigateUp: () -> Unit
) = MyScaffold(R.string.app_lock, onNavigateUp) { ) = MyScaffold(R.string.app_lock, onNavigateUp) {
var password by remember { mutableStateOf("") } var password by rememberSaveable { mutableStateOf(config.password ?: "") }
var confirmPassword by remember { mutableStateOf("") } var confirmPassword by rememberSaveable { mutableStateOf("") }
var allowBiometrics by remember { mutableStateOf(false) } var allowBiometrics by rememberSaveable { mutableStateOf(config.biometrics) }
var lockWhenLeaving by remember { mutableStateOf(false) } var lockWhenLeaving by rememberSaveable { mutableStateOf(config.whenLeaving) }
var alreadySet by remember { mutableStateOf(false) } var alreadySet by rememberSaveable { mutableStateOf(config.password != null) }
val isInputLegal = password.length !in 1..3 && (alreadySet || password.isNotBlank()) val isInputLegal = password.length !in 1..3 && (alreadySet || password.isNotBlank())
LaunchedEffect(Unit) {
val config = getConfig()
password = config.password ?: ""
allowBiometrics = config.biometrics
lockWhenLeaving = config.whenLeaving
alreadySet = config.password != null
}
OutlinedTextField( OutlinedTextField(
password, { password = it }, Modifier.fillMaxWidth().padding(vertical = 4.dp), password, { password = it }, Modifier.fillMaxWidth().padding(vertical = 4.dp),
label = { Text(stringResource(R.string.password)) }, label = { Text(stringResource(R.string.password)) },
@@ -305,7 +296,7 @@ fun ApiSettings(
var alreadyEnabled by remember { mutableStateOf(getEnabled()) } var alreadyEnabled by remember { mutableStateOf(getEnabled()) }
MyScaffold(R.string.api, onNavigateUp) { MyScaffold(R.string.api, onNavigateUp) {
var enabled by remember { mutableStateOf(alreadyEnabled) } var enabled by remember { mutableStateOf(alreadyEnabled) }
var key by remember { mutableStateOf("") } var key by rememberSaveable { mutableStateOf("") }
SwitchItem(R.string.enable, state = enabled, onCheckedChange = { SwitchItem(R.string.enable, state = enabled, onCheckedChange = {
enabled = it enabled = it
}, padding = false) }, padding = false)
@@ -339,15 +330,17 @@ fun ApiSettings(
@Composable @Composable
fun NotificationsScreen( fun NotificationsScreen(
getState: () -> List<NotificationType>, setNotification: (NotificationType, Boolean) -> Unit, enabledNotifications: StateFlow<List<Int>>, getState: () -> Unit,
onNavigateUp: () -> Unit setNotification: (NotificationType, Boolean) -> Unit, onNavigateUp: () -> Unit
) = MyScaffold(R.string.notifications, onNavigateUp, 0.dp) { ) = MyScaffold(R.string.notifications, onNavigateUp, 0.dp) {
val enabledNotifications = remember { mutableStateListOf(*getState().toTypedArray()) } val notifications by enabledNotifications.collectAsStateWithLifecycle()
NotificationType.entries.forEach { type -> LaunchedEffect(Unit) {
SwitchItem(type.text, type in enabledNotifications, { getState()
setNotification(type, it) }
enabledNotifications.run { if (it) plusAssign(type) else minusAssign(type) } NotificationType.entries.filter {
}) it.channel == MyNotificationChannel.Events
}.forEach { type ->
SwitchItem(type.text, type.id in notifications, { setNotification(type, it) })
} }
} }

View File

@@ -5,8 +5,6 @@ import android.content.Intent
import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat import androidx.core.graphics.drawable.IconCompat
import java.security.SecureRandom
import kotlin.io.encoding.Base64
object ShortcutUtils { object ShortcutUtils {
fun setAllShortcuts(context: Context, enabled: Boolean) { fun setAllShortcuts(context: Context, enabled: Boolean) {

View File

@@ -9,8 +9,22 @@ import android.net.Uri
import android.os.Build import android.os.Build
import android.widget.Toast import android.widget.Toast
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.foundation.gestures.awaitEachGesture
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.waitForUpOrCancellation
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.displayCutout
import androidx.compose.foundation.layout.ime
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.union
import androidx.compose.runtime.Composable
import androidx.compose.runtime.saveable.Saver import androidx.compose.runtime.saveable.Saver
import androidx.compose.runtime.saveable.SaverScope import androidx.compose.runtime.saveable.SaverScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.PointerEventPass
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
@@ -91,6 +105,8 @@ fun exportLogs(context: Context, uri: Uri) {
val HorizontalPadding = 16.dp val HorizontalPadding = 16.dp
val BottomPadding = 60.dp
@OptIn(ExperimentalStdlibApi::class) @OptIn(ExperimentalStdlibApi::class)
fun String.hash(): String { fun String.hash(): String {
val md = MessageDigest.getInstance("SHA-256") val md = MessageDigest.getInstance("SHA-256")
@@ -129,3 +145,18 @@ fun generateBase64Key(length: Int): String {
SecureRandom().nextBytes(ba) SecureRandom().nextBytes(ba)
return Base64.withPadding(Base64.PaddingOption.ABSENT).encode(ba) return Base64.withPadding(Base64.PaddingOption.ABSENT).encode(ba)
} }
fun Modifier.clickableTextField(onClick: () -> Unit) =
pointerInput(Unit) {
awaitEachGesture {
awaitFirstDown(pass = PointerEventPass.Initial)
val upEvent = waitForUpOrCancellation(pass = PointerEventPass.Initial)
if (upEvent != null) onClick()
}
}
@Composable
fun adaptiveInsets(): WindowInsets {
val navbar = WindowInsets.navigationBars.only(WindowInsetsSides.Horizontal)
return WindowInsets.ime.union(navbar).union(WindowInsets.displayCutout)
}

View File

@@ -15,15 +15,14 @@ import androidx.compose.foundation.layout.Arrangement
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.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.ime
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyItemScope import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
@@ -53,7 +52,6 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@@ -73,10 +71,12 @@ import androidx.compose.ui.window.DialogProperties
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bintianqi.owndroid.AppInfo import com.bintianqi.owndroid.AppInfo
import com.bintianqi.owndroid.AppInstallerActivity import com.bintianqi.owndroid.AppInstallerActivity
import com.bintianqi.owndroid.BottomPadding
import com.bintianqi.owndroid.HorizontalPadding import com.bintianqi.owndroid.HorizontalPadding
import com.bintianqi.owndroid.MyViewModel import com.bintianqi.owndroid.MyViewModel
import com.bintianqi.owndroid.Privilege import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.adaptiveInsets
import com.bintianqi.owndroid.showOperationResultToast import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.FullWidthRadioButtonItem import com.bintianqi.owndroid.ui.FullWidthRadioButtonItem
import com.bintianqi.owndroid.ui.FunctionItem import com.bintianqi.owndroid.ui.FunctionItem
@@ -156,7 +156,7 @@ fun ApplicationsFeaturesScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Un
scrollBehavior = sb scrollBehavior = sb
) )
}, },
contentWindowInsets = WindowInsets.ime contentWindowInsets = adaptiveInsets()
) { paddingValues -> ) { paddingValues ->
Column( Column(
Modifier Modifier
@@ -231,7 +231,7 @@ fun ApplicationDetailsScreen(
) { ) {
val packageName = param.packageName val packageName = param.packageName
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
var dialog by remember { mutableIntStateOf(0) } // 1: clear storage, 2: uninstall var dialog by rememberSaveable { mutableIntStateOf(0) } // 1: clear storage, 2: uninstall
val info = vm.getAppInfo(packageName) val info = vm.getAppInfo(packageName)
val status by vm.appStatus.collectAsStateWithLifecycle() val status by vm.appStatus.collectAsStateWithLifecycle()
LaunchedEffect(Unit) { vm.getAppStatus(packageName) } LaunchedEffect(Unit) { vm.getAppStatus(packageName) }
@@ -299,8 +299,8 @@ fun PermissionsManagerScreen(
) { ) {
val packageNameParam = param.packageName val packageNameParam = param.packageName
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
var packageName by remember { mutableStateOf(packageNameParam ?: "") } var packageName by rememberSaveable { mutableStateOf(packageNameParam ?: "") }
var selectedPermission by remember { mutableStateOf<PermissionItem?>(null) } var selectedPermission by rememberSaveable { mutableIntStateOf(-1) }
val permissions by packagePermissions.collectAsStateWithLifecycle() val permissions by packagePermissions.collectAsStateWithLifecycle()
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
packageName = chosenPackage.receive() packageName = chosenPackage.receive()
@@ -316,19 +316,19 @@ fun PermissionsManagerScreen(
Spacer(Modifier.padding(vertical = 4.dp)) Spacer(Modifier.padding(vertical = 4.dp))
} }
} }
items(runtimePermissions, { it.permission }) { itemsIndexed(runtimePermissions, { _, it -> it.id }) { index, it ->
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clickable(packageName.isValidPackageName) { .clickable(packageName.isValidPackageName) {
selectedPermission = it selectedPermission = index
} }
.padding(8.dp) .padding(8.dp)
) { ) {
Icon(painterResource(it.icon), null, Modifier.padding(horizontal = 12.dp)) Icon(painterResource(it.icon), null, Modifier.padding(horizontal = 12.dp))
Column { Column {
val state = when(permissions[it.permission]) { val state = when(permissions[it.id]) {
PERMISSION_GRANT_STATE_DEFAULT -> R.string.default_stringres PERMISSION_GRANT_STATE_DEFAULT -> R.string.default_stringres
PERMISSION_GRANT_STATE_GRANTED -> R.string.granted PERMISSION_GRANT_STATE_GRANTED -> R.string.granted
PERMISSION_GRANT_STATE_DENIED -> R.string.denied PERMISSION_GRANT_STATE_DENIED -> R.string.denied
@@ -340,17 +340,18 @@ fun PermissionsManagerScreen(
} }
} }
item { item {
Spacer(Modifier.padding(vertical = 30.dp)) Spacer(Modifier.height(BottomPadding))
} }
} }
if(selectedPermission != null) { if(selectedPermission != -1) {
val permission = runtimePermissions[selectedPermission]
fun changeState(state: Int) { fun changeState(state: Int) {
val result = setPackagePermission(packageName, selectedPermission!!.permission, state) val result = setPackagePermission(packageName, permission.id, state)
if (result) selectedPermission = null if (result) selectedPermission = -1
} }
@Composable @Composable
fun GrantPermissionItem(label: Int, status: Int) { fun GrantPermissionItem(label: Int, status: Int) {
val selected = permissions[selectedPermission!!.permission] == status val selected = permissions[permission.id] == status
Row( Row(
Modifier Modifier
.fillMaxWidth() .fillMaxWidth()
@@ -365,14 +366,14 @@ fun PermissionsManagerScreen(
} }
} }
AlertDialog( AlertDialog(
onDismissRequest = { selectedPermission = null }, onDismissRequest = { selectedPermission = -1 },
confirmButton = { TextButton({ selectedPermission = null }) { Text(stringResource(R.string.cancel)) } }, confirmButton = { TextButton({ selectedPermission = -1 }) { Text(stringResource(R.string.cancel)) } },
title = { Text(stringResource(selectedPermission!!.label)) }, title = { Text(stringResource(permission.label)) },
text = { text = {
Column { Column {
Text(selectedPermission!!.permission) Text(permission.id)
Spacer(Modifier.padding(vertical = 4.dp)) Spacer(Modifier.padding(vertical = 4.dp))
if(!(VERSION.SDK_INT >= 31 && selectedPermission!!.profileOwnerRestricted && privilege.profile)) { if(!(VERSION.SDK_INT >= 31 && permission.profileOwnerRestricted && privilege.profile)) {
GrantPermissionItem(R.string.granted, PERMISSION_GRANT_STATE_GRANTED) GrantPermissionItem(R.string.granted, PERMISSION_GRANT_STATE_GRANTED)
} }
GrantPermissionItem(R.string.denied, PERMISSION_GRANT_STATE_DENIED) GrantPermissionItem(R.string.denied, PERMISSION_GRANT_STATE_DENIED)
@@ -393,8 +394,8 @@ fun ClearAppStorageScreen(
chosenPackage: Channel<String>, onChoosePackage: () -> Unit, chosenPackage: Channel<String>, onChoosePackage: () -> Unit,
onClear: (String, (Boolean) -> Unit) -> Unit, onNavigateUp: () -> Unit onClear: (String, (Boolean) -> Unit) -> Unit, onNavigateUp: () -> Unit
) { ) {
var dialog by remember { mutableStateOf(false) } var dialog by rememberSaveable { mutableStateOf(false) }
var packageName by remember { mutableStateOf("") } var packageName by rememberSaveable { mutableStateOf("") }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
packageName = chosenPackage.receive() packageName = chosenPackage.receive()
} }
@@ -418,7 +419,7 @@ private fun ClearAppStorageDialog(
packageName: String, onClear: (String, (Boolean) -> Unit) -> Unit, onClose: () -> Unit packageName: String, onClear: (String, (Boolean) -> Unit) -> Unit, onClose: () -> Unit
) { ) {
val context = LocalContext.current val context = LocalContext.current
var clearing by remember { mutableStateOf(false) } var clearing by rememberSaveable { mutableStateOf(false) }
AlertDialog( AlertDialog(
title = { Text(stringResource(R.string.clear_app_storage)) }, title = { Text(stringResource(R.string.clear_app_storage)) },
text = { text = {
@@ -457,8 +458,8 @@ fun UninstallAppScreen(
chosenPackage: Channel<String>, onChoosePackage: () -> Unit, chosenPackage: Channel<String>, onChoosePackage: () -> Unit,
onUninstall: (String, (String?) -> Unit) -> Unit, onNavigateUp: () -> Unit onUninstall: (String, (String?) -> Unit) -> Unit, onNavigateUp: () -> Unit
) { ) {
var dialog by remember { mutableStateOf(false) } var dialog by rememberSaveable { mutableStateOf(false) }
var packageName by remember { mutableStateOf("") } var packageName by rememberSaveable { mutableStateOf("") }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
packageName = chosenPackage.receive() packageName = chosenPackage.receive()
} }
@@ -483,8 +484,8 @@ fun UninstallAppScreen(
private fun UninstallAppDialog( private fun UninstallAppDialog(
packageName: String, onUninstall: (String, (String?) -> Unit) -> Unit, onClose: () -> Unit packageName: String, onUninstall: (String, (String?) -> Unit) -> Unit, onClose: () -> Unit
) { ) {
var uninstalling by remember { mutableStateOf(false) } var uninstalling by rememberSaveable { mutableStateOf(false) }
var errorMessage by remember { mutableStateOf<String?>(null) } var errorMessage by rememberSaveable { mutableStateOf<String?>(null) }
AlertDialog( AlertDialog(
title = { Text(stringResource(R.string.uninstall)) }, title = { Text(stringResource(R.string.uninstall)) },
text = { text = {
@@ -525,7 +526,7 @@ fun InstallExistingAppScreen(
onInstall: (String) -> Boolean, onNavigateUp: () -> Unit onInstall: (String) -> Boolean, onNavigateUp: () -> Unit
) { ) {
val context = LocalContext.current val context = LocalContext.current
var packageName by remember { mutableStateOf("") } var packageName by rememberSaveable { mutableStateOf("") }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
packageName = chosenPackage.receive() packageName = chosenPackage.receive()
} }
@@ -561,7 +562,7 @@ fun CredentialManagerPolicyScreen(
val context = LocalContext.current val context = LocalContext.current
var policy by rememberSaveable { mutableIntStateOf(getCmPolicy()) } var policy by rememberSaveable { mutableIntStateOf(getCmPolicy()) }
val packages by cmPackages.collectAsStateWithLifecycle() val packages by cmPackages.collectAsStateWithLifecycle()
var packageName by remember { mutableStateOf("") } var packageName by rememberSaveable { mutableStateOf("") }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
packageName = chosenPackage.receive() packageName = chosenPackage.receive()
} }
@@ -623,7 +624,7 @@ fun PermittedAsAndImPackages(
) { ) {
val context = LocalContext.current val context = LocalContext.current
val packages by packagesState.collectAsStateWithLifecycle() val packages by packagesState.collectAsStateWithLifecycle()
var packageName by remember { mutableStateOf("") } var packageName by rememberSaveable { mutableStateOf("") }
var allowAll by rememberSaveable { mutableStateOf(getPackages()) } var allowAll by rememberSaveable { mutableStateOf(getPackages()) }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
packageName = chosenPackage.receive() packageName = chosenPackage.receive()
@@ -673,7 +674,7 @@ fun EnableSystemAppScreen(
onEnable: (String) -> Unit, onNavigateUp: () -> Unit onEnable: (String) -> Unit, onNavigateUp: () -> Unit
) { ) {
val context = LocalContext.current val context = LocalContext.current
var packageName by remember { mutableStateOf("") } var packageName by rememberSaveable { mutableStateOf("") }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
packageName = chosenPackage.receive() packageName = chosenPackage.receive()
} }
@@ -704,7 +705,7 @@ fun SetDefaultDialerScreen(
chosenPackage: Channel<String>, onChoosePackage: () -> Unit, chosenPackage: Channel<String>, onChoosePackage: () -> Unit,
onSet: (String) -> Unit, onNavigateUp: () -> Unit onSet: (String) -> Unit, onNavigateUp: () -> Unit
) { ) {
var packageName by remember { mutableStateOf("") } var packageName by rememberSaveable { mutableStateOf("") }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
packageName = chosenPackage.receive() packageName = chosenPackage.receive()
} }
@@ -743,7 +744,7 @@ fun PackageFunctionScreen(
chosenPackage: Channel<String>, onChoosePackage: () -> Unit, notes: Int? = null chosenPackage: Channel<String>, onChoosePackage: () -> Unit, notes: Int? = null
) { ) {
val packages by packagesState.collectAsStateWithLifecycle() val packages by packagesState.collectAsStateWithLifecycle()
var packageName by remember { mutableStateOf("") } var packageName by rememberSaveable { mutableStateOf("") }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
onGet() onGet()
packageName = chosenPackage.receive() packageName = chosenPackage.receive()

View File

@@ -15,7 +15,6 @@ import android.os.Build.VERSION
import android.util.Log import android.util.Log
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import com.bintianqi.owndroid.MyApplication import com.bintianqi.owndroid.MyApplication
import com.bintianqi.owndroid.MyNotificationChannel
import com.bintianqi.owndroid.NotificationType import com.bintianqi.owndroid.NotificationType
import com.bintianqi.owndroid.NotificationUtils import com.bintianqi.owndroid.NotificationUtils
import com.bintianqi.owndroid.Privilege import com.bintianqi.owndroid.Privilege
@@ -93,7 +92,7 @@ fun Context.getPackageInstaller(): PackageInstaller {
val dhizukuErrorStatus = MutableStateFlow(0) val dhizukuErrorStatus = MutableStateFlow(0)
data class PermissionItem( data class PermissionItem(
val permission: String, val id: String,
val label: Int, val label: Int,
val icon: Int, val icon: Int,
val profileOwnerRestricted: Boolean = false, val profileOwnerRestricted: Boolean = false,
@@ -497,7 +496,7 @@ fun retrieveSecurityLogs(app: MyApplication) {
val logs = Privilege.DPM.retrieveSecurityLogs(Privilege.DAR) ?: return@launch val logs = Privilege.DPM.retrieveSecurityLogs(Privilege.DAR) ?: return@launch
app.myRepo.writeSecurityLogs(logs) app.myRepo.writeSecurityLogs(logs)
NotificationUtils.sendBasicNotification( NotificationUtils.sendBasicNotification(
app, NotificationType.SecurityLogsCollected, MyNotificationChannel.SecurityLogging, app, NotificationType.SecurityLogsCollected,
app.getString(R.string.n_logs_in_total, logs.size) app.getString(R.string.n_logs_in_total, logs.size)
) )
} }

View File

@@ -24,18 +24,14 @@ import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box 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.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.ime
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.itemsIndexed
@@ -65,6 +61,7 @@ import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.FilledTonalButton import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.FilledTonalIconButton import androidx.compose.material3.FilledTonalIconButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
@@ -113,12 +110,13 @@ import com.bintianqi.owndroid.HorizontalPadding
import com.bintianqi.owndroid.MyViewModel import com.bintianqi.owndroid.MyViewModel
import com.bintianqi.owndroid.Privilege import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.formatFileSize import com.bintianqi.owndroid.clickableTextField
import com.bintianqi.owndroid.formatDate import com.bintianqi.owndroid.formatDate
import com.bintianqi.owndroid.formatFileSize
import com.bintianqi.owndroid.adaptiveInsets
import com.bintianqi.owndroid.popToast import com.bintianqi.owndroid.popToast
import com.bintianqi.owndroid.showOperationResultToast import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.ErrorDialog import com.bintianqi.owndroid.ui.ErrorDialog
import com.bintianqi.owndroid.ui.ExpandExposedTextFieldIcon
import com.bintianqi.owndroid.ui.FullWidthCheckBoxItem import com.bintianqi.owndroid.ui.FullWidthCheckBoxItem
import com.bintianqi.owndroid.ui.FullWidthRadioButtonItem import com.bintianqi.owndroid.ui.FullWidthRadioButtonItem
import com.bintianqi.owndroid.ui.FunctionItem import com.bintianqi.owndroid.ui.FunctionItem
@@ -181,8 +179,8 @@ fun NetworkOptionsScreen(
getLanEnabled: () -> Boolean, setLanEnabled: (Boolean) -> Unit, onNavigateUp: () -> Unit getLanEnabled: () -> Boolean, setLanEnabled: (Boolean) -> Unit, onNavigateUp: () -> Unit
) { ) {
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
var dialog by remember { mutableIntStateOf(0) } var dialog by rememberSaveable { mutableIntStateOf(0) }
var lanEnabled by remember { mutableStateOf(getLanEnabled()) } var lanEnabled by rememberSaveable { mutableStateOf(getLanEnabled()) }
MyScaffold(R.string.options, onNavigateUp, 0.dp) { MyScaffold(R.string.options, onNavigateUp, 0.dp) {
if(VERSION.SDK_INT >= 30 && (privilege.device || privilege.org)) { if(VERSION.SDK_INT >= 30 && (privilege.device || privilege.org)) {
SwitchItem(R.string.lockdown_admin_configured_network, icon = R.drawable.wifi_password_fill0, SwitchItem(R.string.lockdown_admin_configured_network, icon = R.drawable.wifi_password_fill0,
@@ -224,7 +222,7 @@ fun WifiScreen(
colors = TopAppBarDefaults.topAppBarColors(MaterialTheme.colorScheme.surfaceContainer) colors = TopAppBarDefaults.topAppBarColors(MaterialTheme.colorScheme.surfaceContainer)
) )
}, },
contentWindowInsets = WindowInsets.ime contentWindowInsets = adaptiveInsets()
) { paddingValues -> ) { paddingValues ->
Column( Column(
modifier = Modifier.fillMaxSize().padding(paddingValues) modifier = Modifier.fillMaxSize().padding(paddingValues)
@@ -266,7 +264,7 @@ fun WifiOverviewScreen(
) { ) {
val context = LocalContext.current val context = LocalContext.current
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
var macDialog by remember { mutableStateOf(false) } var macDialog by rememberSaveable { mutableStateOf(false) }
Column(Modifier.fillMaxSize()) { Column(Modifier.fillMaxSize()) {
Spacer(Modifier.height(10.dp)) Spacer(Modifier.height(10.dp))
Row( Row(
@@ -384,7 +382,7 @@ private fun SavedNetworks(
removeNetwork: (Int) -> Boolean, editNetwork: (Int) -> Unit removeNetwork: (Int) -> Boolean, editNetwork: (Int) -> Unit
) { ) {
val context = LocalContext.current val context = LocalContext.current
var dialog by remember { mutableIntStateOf(-1) } var dialog by rememberSaveable { mutableIntStateOf(-1) }
val list by configuredNetworks.collectAsStateWithLifecycle() val list by configuredNetworks.collectAsStateWithLifecycle()
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
getConfiguredNetworks() getConfiguredNetworks()
@@ -513,7 +511,7 @@ fun UpdateNetworkScreen(info: WifiInfo, setNetwork: (WifiInfo) -> Boolean, onNav
colors = TopAppBarDefaults.topAppBarColors(MaterialTheme.colorScheme.surfaceContainer) colors = TopAppBarDefaults.topAppBarColors(MaterialTheme.colorScheme.surfaceContainer)
) )
}, },
contentWindowInsets = WindowInsets.ime contentWindowInsets = adaptiveInsets()
) { paddingValues -> ) { paddingValues ->
Column( Column(
modifier = Modifier.fillMaxSize().padding(paddingValues) modifier = Modifier.fillMaxSize().padding(paddingValues)
@@ -537,21 +535,21 @@ private fun AddNetworkScreen(
val context = LocalContext.current val context = LocalContext.current
val fm = LocalFocusManager.current val fm = LocalFocusManager.current
/** 0: None, 1:Status, 2:Security, 3:MAC randomization, 4:Static IP, 5:Proxy, 6:Hidden SSID */ /** 0: None, 1:Status, 2:Security, 3:MAC randomization, 4:Static IP, 5:Proxy, 6:Hidden SSID */
var menu by remember { mutableIntStateOf(0) } var menu by rememberSaveable { mutableIntStateOf(0) }
var status by remember { mutableStateOf(WifiStatus.Enabled) } var status by rememberSaveable { mutableStateOf(WifiStatus.Enabled) }
var ssid by remember { mutableStateOf("") } var ssid by rememberSaveable { mutableStateOf("") }
var hiddenSsid by remember { mutableStateOf<Boolean?>(false) } var hiddenSsid by rememberSaveable { mutableStateOf<Boolean?>(false) }
var security by remember { mutableStateOf<WifiSecurity?>(WifiSecurity.Open) } var security by rememberSaveable { mutableStateOf<WifiSecurity?>(WifiSecurity.Open) }
var password by remember { mutableStateOf("") } var password by rememberSaveable { mutableStateOf("") }
var macRandomization by remember { mutableStateOf<WifiMacRandomization?>(WifiMacRandomization.None) } var macRandomization by rememberSaveable { mutableStateOf<WifiMacRandomization?>(WifiMacRandomization.None) }
var ipMode by remember { mutableStateOf<IpMode?>(IpMode.Dhcp) } var ipMode by rememberSaveable { mutableStateOf<IpMode?>(IpMode.Dhcp) }
var ipAddress by remember { mutableStateOf("") } var ipAddress by rememberSaveable { mutableStateOf("") }
var gatewayAddress by remember { mutableStateOf("") } var gatewayAddress by rememberSaveable { mutableStateOf("") }
var dnsServers by remember { mutableStateOf("") } var dnsServers by rememberSaveable { mutableStateOf("") }
var proxyMode by remember { mutableStateOf<ProxyMode?>(ProxyMode.None) } var proxyMode by rememberSaveable { mutableStateOf<ProxyMode?>(ProxyMode.None) }
var httpProxyHost by remember { mutableStateOf("") } var httpProxyHost by rememberSaveable { mutableStateOf("") }
var httpProxyPort by remember { mutableStateOf("") } var httpProxyPort by rememberSaveable { mutableStateOf("") }
var httpProxyExclList by remember { mutableStateOf("") } var httpProxyExclList by rememberSaveable { mutableStateOf("") }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
if (updating) { if (updating) {
hiddenSsid = null hiddenSsid = null
@@ -575,7 +573,7 @@ private fun AddNetworkScreen(
Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(), Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(),
readOnly = true, readOnly = true,
label = { Text(stringResource(R.string.status)) }, label = { Text(stringResource(R.string.status)) },
trailingIcon = { ExpandExposedTextFieldIcon(menu == 1) }, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(menu == 1) },
) )
ExposedDropdownMenu(menu == 1, { menu = 0 }) { ExposedDropdownMenu(menu == 1, { menu = 0 }) {
WifiStatus.entries.forEach { WifiStatus.entries.forEach {
@@ -600,7 +598,7 @@ private fun AddNetworkScreen(
stringResource(hiddenSsid?.yesOrNo ?: R.string.unchanged), {}, stringResource(hiddenSsid?.yesOrNo ?: R.string.unchanged), {},
Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(), Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(),
readOnly = true, label = { Text(stringResource(R.string.hidden_ssid)) }, readOnly = true, label = { Text(stringResource(R.string.hidden_ssid)) },
trailingIcon = { ExpandExposedTextFieldIcon(menu == 1) } trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(menu == 1) }
) )
DropdownMenu(menu == 6, { menu = 0 }) { DropdownMenu(menu == 6, { menu = 0 }) {
if (updating) DropdownMenuItem( if (updating) DropdownMenuItem(
@@ -633,7 +631,7 @@ private fun AddNetworkScreen(
stringResource(security?.text ?: R.string.unchanged), {}, stringResource(security?.text ?: R.string.unchanged), {},
Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(), Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(),
readOnly = true, label = { Text(stringResource(R.string.security)) }, readOnly = true, label = { Text(stringResource(R.string.security)) },
trailingIcon = { ExpandExposedTextFieldIcon(menu == 1) } trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(menu == 1) }
) )
ExposedDropdownMenu(menu == 2, { menu = 0 }) { ExposedDropdownMenu(menu == 2, { menu = 0 }) {
if (updating) UnchangedMenuItem { security = null } if (updating) UnchangedMenuItem { security = null }
@@ -662,7 +660,7 @@ private fun AddNetworkScreen(
stringResource(macRandomization?.text ?: R.string.unchanged), {}, stringResource(macRandomization?.text ?: R.string.unchanged), {},
Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(), Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(),
readOnly = true, label = { Text(stringResource(R.string.mac_randomization)) }, readOnly = true, label = { Text(stringResource(R.string.mac_randomization)) },
trailingIcon = { ExpandExposedTextFieldIcon(menu == 3) }, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(menu == 3) },
) )
ExposedDropdownMenu(menu == 3, { menu = 0 }) { ExposedDropdownMenu(menu == 3, { menu = 0 }) {
if (updating) UnchangedMenuItem { macRandomization = null } if (updating) UnchangedMenuItem { macRandomization = null }
@@ -686,7 +684,7 @@ private fun AddNetworkScreen(
stringResource(ipMode?.text ?: R.string.unchanged), {}, stringResource(ipMode?.text ?: R.string.unchanged), {},
Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(), Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(),
readOnly = true, label = { Text(stringResource(R.string.ip_settings)) }, readOnly = true, label = { Text(stringResource(R.string.ip_settings)) },
trailingIcon = { ExpandExposedTextFieldIcon(menu == 4) }, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(menu == 4) },
) )
ExposedDropdownMenu(menu == 4, { menu = 0 }) { ExposedDropdownMenu(menu == 4, { menu = 0 }) {
if (updating) UnchangedMenuItem { ipMode = null } if (updating) UnchangedMenuItem { ipMode = null }
@@ -737,7 +735,7 @@ private fun AddNetworkScreen(
stringResource(proxyMode?.text ?: R.string.unchanged), {}, stringResource(proxyMode?.text ?: R.string.unchanged), {},
Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(), Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(),
readOnly = true, label = { Text(stringResource(R.string.proxy)) }, readOnly = true, label = { Text(stringResource(R.string.proxy)) },
trailingIcon = { ExpandExposedTextFieldIcon(menu == 5) }, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(menu == 5) },
) )
ExposedDropdownMenu(menu == 5, { menu = 0 }) { ExposedDropdownMenu(menu == 5, { menu = 0 }) {
if (updating) UnchangedMenuItem { proxyMode = null } if (updating) UnchangedMenuItem { proxyMode = null }
@@ -783,19 +781,29 @@ private fun AddNetworkScreen(
} }
Button( Button(
onClick = { onClick = {
val proxyConf = if (proxyMode == ProxyMode.Http) {
ProxyConf(
httpProxyHost, httpProxyPort.toInt(),
httpProxyExclList.lines().filter { it.isNotBlank() }
)
} else null
val ipConf = if (ipMode == IpMode.Static) {
IpConf(ipAddress, gatewayAddress, dnsServers.lines().filter { it.isNotBlank() })
} else null
val result = setNetwork(WifiInfo( val result = setNetwork(WifiInfo(
-1, ssid, hiddenSsid, "", macRandomization, status, security, password, ipMode, -1, ssid, hiddenSsid, "", macRandomization, status, security, password, ipMode,
IpConf(ipAddress, gatewayAddress, dnsServers.lines().filter { it.isNotBlank() }), ipConf, proxyMode, proxyConf
proxyMode, ProxyConf(httpProxyHost, httpProxyPort.toInt(), httpProxyExclList.lines().filter { it.isNotBlank() })
)) ))
context.showOperationResultToast(result) context.showOperationResultToast(result)
if (result) onNavigateUp() if (result) onNavigateUp()
}, },
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp) modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp),
enabled = (proxyMode != ProxyMode.Http ||
(httpProxyPort.toIntOrNull() != null && httpProxyHost.isNotBlank()))
) { ) {
Text(stringResource(if (updating) R.string.update else R.string.add)) Text(stringResource(if (updating) R.string.update else R.string.add))
} }
Spacer(Modifier.height(40.dp)) Spacer(Modifier.height(60.dp))
} }
} }
@@ -807,7 +815,7 @@ fun WifiSecurityLevelScreen(
getLevel: () -> Int, setLevel: (Int) -> Unit, onNavigateUp: () -> Unit getLevel: () -> Int, setLevel: (Int) -> Unit, onNavigateUp: () -> Unit
) { ) {
val context = LocalContext.current val context = LocalContext.current
var level by remember { mutableIntStateOf(getLevel()) } var level by rememberSaveable { mutableIntStateOf(getLevel()) }
MyScaffold(R.string.min_wifi_security_level, onNavigateUp, 0.dp) { MyScaffold(R.string.min_wifi_security_level, onNavigateUp, 0.dp) {
FullWidthRadioButtonItem(R.string.wifi_security_open, level == WIFI_SECURITY_OPEN) { level = WIFI_SECURITY_OPEN } FullWidthRadioButtonItem(R.string.wifi_security_open, level == WIFI_SECURITY_OPEN) { level = WIFI_SECURITY_OPEN }
FullWidthRadioButtonItem("WEP, WPA(2)-PSK", level == WIFI_SECURITY_PERSONAL) { level = WIFI_SECURITY_PERSONAL } FullWidthRadioButtonItem("WEP, WPA(2)-PSK", level == WIFI_SECURITY_PERSONAL) { level = WIFI_SECURITY_PERSONAL }
@@ -845,8 +853,8 @@ fun WifiSsidPolicyScreen(
val context = LocalContext.current val context = LocalContext.current
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
MyScaffold(R.string.wifi_ssid_policy, onNavigateUp, 0.dp) { MyScaffold(R.string.wifi_ssid_policy, onNavigateUp, 0.dp) {
var type by remember { mutableStateOf(SsidPolicyType.None) } var type by rememberSaveable { mutableStateOf(SsidPolicyType.None) }
val list = remember { mutableStateListOf<String>() } val list = rememberSaveable { mutableStateListOf<String>() }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
getPolicy().let { getPolicy().let {
type = it.type type = it.type
@@ -959,11 +967,7 @@ fun NetworkStatsScreen(
var uid by rememberSaveable { mutableIntStateOf(NetworkStats.Bucket.UID_ALL) } var uid by rememberSaveable { mutableIntStateOf(NetworkStats.Bucket.UID_ALL) }
var tag by rememberSaveable { mutableIntStateOf(NetworkStats.Bucket.TAG_NONE) } var tag by rememberSaveable { mutableIntStateOf(NetworkStats.Bucket.TAG_NONE) }
var state by rememberSaveable { mutableStateOf(NetworkStatsState.All) } var state by rememberSaveable { mutableStateOf(NetworkStatsState.All) }
val startTimeIs = remember { MutableInteractionSource() } var errorMessage by rememberSaveable { mutableStateOf<String?>(null) }
val endTimeIs = remember { MutableInteractionSource() }
if (startTimeIs.collectIsPressedAsState().value) menu = NetworkStatsMenu.StartTime
if (endTimeIs.collectIsPressedAsState().value) menu = NetworkStatsMenu.EndTime
var errorMessage by remember { mutableStateOf<String?>(null) }
MyScaffold(R.string.network_stats, onNavigateUp) { MyScaffold(R.string.network_stats, onNavigateUp) {
ExposedDropdownMenuBox( ExposedDropdownMenuBox(
menu == NetworkStatsMenu.Type, menu == NetworkStatsMenu.Type,
@@ -974,7 +978,9 @@ fun NetworkStatsScreen(
stringResource(type.text), {}, stringResource(type.text), {},
Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(), Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(),
readOnly = true, label = { Text(stringResource(R.string.type)) }, readOnly = true, label = { Text(stringResource(R.string.type)) },
trailingIcon = { ExpandExposedTextFieldIcon(menu == NetworkStatsMenu.Type) } trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(menu == NetworkStatsMenu.Type)
}
) )
ExposedDropdownMenu( ExposedDropdownMenu(
menu == NetworkStatsMenu.Type, { menu = NetworkStatsMenu.None } menu == NetworkStatsMenu.Type, { menu = NetworkStatsMenu.None }
@@ -1001,7 +1007,9 @@ fun NetworkStatsScreen(
stringResource(target.text), {}, stringResource(target.text), {},
Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(), Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(),
readOnly = true, label = { Text(stringResource(R.string.target)) }, readOnly = true, label = { Text(stringResource(R.string.target)) },
trailingIcon = { ExpandExposedTextFieldIcon(menu == NetworkStatsMenu.Target) } trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(menu == NetworkStatsMenu.Target)
}
) )
ExposedDropdownMenu( ExposedDropdownMenu(
menu == NetworkStatsMenu.Target, { menu = NetworkStatsMenu.None } menu == NetworkStatsMenu.Target, { menu = NetworkStatsMenu.None }
@@ -1028,7 +1036,9 @@ fun NetworkStatsScreen(
stringResource(networkType.text), {}, stringResource(networkType.text), {},
Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(), Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(),
readOnly = true, label = { Text(stringResource(R.string.network_type)) }, readOnly = true, label = { Text(stringResource(R.string.network_type)) },
trailingIcon = { ExpandExposedTextFieldIcon(menu == NetworkStatsMenu.NetworkType) } trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(menu == NetworkStatsMenu.NetworkType)
}
) )
ExposedDropdownMenu( ExposedDropdownMenu(
menu == NetworkStatsMenu.NetworkType, { menu = NetworkStatsMenu.None } menu == NetworkStatsMenu.NetworkType, { menu = NetworkStatsMenu.None }
@@ -1045,18 +1055,22 @@ fun NetworkStatsScreen(
} }
} }
OutlinedTextField( OutlinedTextField(
value = startTime.let { if(it == -1L) "" else formatDate(it) }, onValueChange = {}, readOnly = true, formatDate(startTime), {},
label = { Text(stringResource(R.string.start_time)) }, Modifier
interactionSource = startTimeIs, .fillMaxWidth()
isError = startTime >= endTime, .clickableTextField { menu = NetworkStatsMenu.StartTime }
modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp) .padding(bottom = 4.dp),
readOnly = true, label = { Text(stringResource(R.string.start_time)) },
isError = startTime >= endTime
) )
OutlinedTextField( OutlinedTextField(
value = formatDate(endTime), onValueChange = {}, readOnly = true, formatDate(endTime), {},
label = { Text(stringResource(R.string.end_time)) }, Modifier
interactionSource = endTimeIs, .fillMaxWidth()
isError = startTime >= endTime, .clickableTextField { menu = NetworkStatsMenu.EndTime }
modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp) .padding(bottom = 4.dp),
readOnly = true, label = { Text(stringResource(R.string.end_time)) },
isError = startTime >= endTime
) )
if(target == NetworkStatsTarget.Uid || target == NetworkStatsTarget.UidTag || target == NetworkStatsTarget.UidTagState) if(target == NetworkStatsTarget.Uid || target == NetworkStatsTarget.UidTag || target == NetworkStatsTarget.UidTagState)
ExposedDropdownMenuBox( ExposedDropdownMenuBox(
@@ -1077,7 +1091,7 @@ fun NetworkStatsScreen(
it.toIntOrNull()?.let { num -> uid = num } it.toIntOrNull()?.let { num -> uid = num }
}, },
readOnly = readOnly, label = { Text(stringResource(R.string.uid)) }, readOnly = readOnly, label = { Text(stringResource(R.string.uid)) },
trailingIcon = { ExpandExposedTextFieldIcon(menu == NetworkStatsMenu.Uid) }, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(menu == NetworkStatsMenu.Uid) },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
isError = !readOnly && uidText.toIntOrNull() == null, isError = !readOnly && uidText.toIntOrNull() == null,
modifier = Modifier modifier = Modifier
@@ -1131,7 +1145,9 @@ fun NetworkStatsScreen(
it.toIntOrNull()?.let { num -> tag = num } it.toIntOrNull()?.let { num -> tag = num }
}, },
readOnly = readOnly, label = { Text(stringResource(R.string.uid)) }, readOnly = readOnly, label = { Text(stringResource(R.string.uid)) },
trailingIcon = { ExpandExposedTextFieldIcon(menu == NetworkStatsMenu.Tag) }, trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(menu == NetworkStatsMenu.Tag)
},
isError = !readOnly && tagText.toIntOrNull() == null, isError = !readOnly && tagText.toIntOrNull() == null,
modifier = Modifier modifier = Modifier
.menuAnchor(if(readOnly) MenuAnchorType.PrimaryNotEditable else MenuAnchorType.PrimaryEditable) .menuAnchor(if(readOnly) MenuAnchorType.PrimaryNotEditable else MenuAnchorType.PrimaryEditable)
@@ -1168,7 +1184,9 @@ fun NetworkStatsScreen(
stringResource(state.text), {}, stringResource(state.text), {},
Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(), Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(),
readOnly = true, label = { Text(stringResource(R.string.uid)) }, readOnly = true, label = { Text(stringResource(R.string.uid)) },
trailingIcon = { ExpandExposedTextFieldIcon(menu == NetworkStatsMenu.State) } trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(menu == NetworkStatsMenu.State)
}
) )
ExposedDropdownMenu( ExposedDropdownMenu(
menu == NetworkStatsMenu.State, { menu = NetworkStatsMenu.None } menu == NetworkStatsMenu.State, { menu = NetworkStatsMenu.None }
@@ -1251,7 +1269,7 @@ data class NetworkStatsData(
fun NetworkStatsViewerScreen( fun NetworkStatsViewerScreen(
data: List<NetworkStatsData>, clearData: () -> Unit, onNavigateUp: () -> Unit data: List<NetworkStatsData>, clearData: () -> Unit, onNavigateUp: () -> Unit
) { ) {
var index by remember { mutableIntStateOf(0) } var index by rememberSaveable { mutableIntStateOf(0) }
val size = data.size val size = data.size
val ps = rememberPagerState { size } val ps = rememberPagerState { size }
index = ps.currentPage index = ps.currentPage
@@ -1362,7 +1380,7 @@ fun PrivateDnsScreen(
val context = LocalContext.current val context = LocalContext.current
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var mode by remember { mutableStateOf<PrivateDnsMode?>(PrivateDnsMode.Opportunistic) } var mode by remember { mutableStateOf<PrivateDnsMode?>(PrivateDnsMode.Opportunistic) }
var inputHost by remember { mutableStateOf("") } var inputHost by rememberSaveable { mutableStateOf("") }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
val conf = getPrivateDns() val conf = getPrivateDns()
mode = conf.mode mode = conf.mode
@@ -1451,12 +1469,12 @@ fun RecommendedGlobalProxyScreen(
) { ) {
val context = LocalContext.current val context = LocalContext.current
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var type by remember { mutableStateOf(ProxyType.Off) } var type by rememberSaveable { mutableStateOf(ProxyType.Off) }
var pacUrl by remember { mutableStateOf("") } var pacUrl by rememberSaveable { mutableStateOf("") }
var specifyPort by remember { mutableStateOf(false) } var specifyPort by rememberSaveable { mutableStateOf(false) }
var host by remember { mutableStateOf("") } var host by rememberSaveable { mutableStateOf("") }
var port by remember { mutableStateOf("") } var port by rememberSaveable { mutableStateOf("") }
var exclList by remember { mutableStateOf("") } var exclList by rememberSaveable { mutableStateOf("") }
MyScaffold(R.string.recommended_global_proxy, onNavigateUp, 0.dp) { MyScaffold(R.string.recommended_global_proxy, onNavigateUp, 0.dp) {
ProxyType.entries.forEach { ProxyType.entries.forEach {
FullWidthRadioButtonItem(it.text, type == it) { type = it } FullWidthRadioButtonItem(it.text, type == it) { type = it }
@@ -1576,7 +1594,7 @@ fun PreferentialNetworkServiceScreen(
pnsConfigs: StateFlow<List<PreferentialNetworkServiceInfo>>, getConfigs: () -> Unit, pnsConfigs: StateFlow<List<PreferentialNetworkServiceInfo>>, getConfigs: () -> Unit,
onNavigateUp: () -> Unit, onNavigate: (AddPreferentialNetworkServiceConfig) -> Unit onNavigateUp: () -> Unit, onNavigate: (AddPreferentialNetworkServiceConfig) -> Unit
) { ) {
var masterEnabled by remember { mutableStateOf(getEnabled()) } var masterEnabled by rememberSaveable { mutableStateOf(getEnabled()) }
val configs by pnsConfigs.collectAsStateWithLifecycle() val configs by pnsConfigs.collectAsStateWithLifecycle()
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
getConfigs() getConfigs()
@@ -1633,12 +1651,12 @@ fun AddPreferentialNetworkServiceConfigScreen(
setConfig: (PreferentialNetworkServiceInfo, Boolean) -> Unit, onNavigateUp: () -> Unit setConfig: (PreferentialNetworkServiceInfo, Boolean) -> Unit, onNavigateUp: () -> Unit
) { ) {
val updateMode = origin.id != -1 val updateMode = origin.id != -1
var enabled by remember { mutableStateOf(origin.enabled) } var enabled by rememberSaveable { mutableStateOf(origin.enabled) }
var id by remember { mutableIntStateOf(origin.id) } var id by rememberSaveable { mutableIntStateOf(origin.id) }
var allowFallback by remember { mutableStateOf(origin.allowFallback) } var allowFallback by rememberSaveable { mutableStateOf(origin.allowFallback) }
var blockNonMatching by remember { mutableStateOf(origin.blockNonMatching) } var blockNonMatching by rememberSaveable { mutableStateOf(origin.blockNonMatching) }
var excludedUids by remember { mutableStateOf(origin.excludedUids.joinToString("\n")) } var excludedUids by rememberSaveable { mutableStateOf(origin.excludedUids.joinToString("\n")) }
var includedUids by remember { mutableStateOf(origin.includedUids.joinToString("\n")) } var includedUids by rememberSaveable { mutableStateOf(origin.includedUids.joinToString("\n")) }
var dropdown by remember { mutableStateOf(false) } var dropdown by remember { mutableStateOf(false) }
MySmallTitleScaffold(R.string.preferential_network_service, onNavigateUp) { MySmallTitleScaffold(R.string.preferential_network_service, onNavigateUp) {
SwitchItem(title = R.string.enabled, state = enabled, onCheckedChange = { enabled = it }, padding = false) SwitchItem(title = R.string.enabled, state = enabled, onCheckedChange = { enabled = it }, padding = false)
@@ -1647,7 +1665,7 @@ fun AddPreferentialNetworkServiceConfigScreen(
if (id == -1) "" else id.toString(), {}, if (id == -1) "" else id.toString(), {},
Modifier.fillMaxWidth().menuAnchor(MenuAnchorType.PrimaryNotEditable), Modifier.fillMaxWidth().menuAnchor(MenuAnchorType.PrimaryNotEditable),
readOnly = true, label = { Text("id") }, readOnly = true, label = { Text("id") },
trailingIcon = { ExpandExposedTextFieldIcon(dropdown) } trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(dropdown) }
) )
ExposedDropdownMenu(dropdown, { dropdown = false }) { ExposedDropdownMenu(dropdown, { dropdown = false }) {
for (i in 1..5) { for (i in 1..5) {
@@ -1724,7 +1742,7 @@ fun OverrideApnScreen(
apnConfigs: StateFlow<List<ApnConfig>>, getConfigs: () -> Unit, getEnabled: () -> Boolean, apnConfigs: StateFlow<List<ApnConfig>>, getConfigs: () -> Unit, getEnabled: () -> Boolean,
setEnabled: (Boolean) -> Unit, onNavigateUp: () -> Unit, onNavigateToAddSetting: (Int) -> Unit setEnabled: (Boolean) -> Unit, onNavigateUp: () -> Unit, onNavigateToAddSetting: (Int) -> Unit
) { ) {
var enabled by remember { mutableStateOf(getEnabled()) } var enabled by rememberSaveable { mutableStateOf(getEnabled()) }
val configs by apnConfigs.collectAsStateWithLifecycle() val configs by apnConfigs.collectAsStateWithLifecycle()
LaunchedEffect(Unit) { getConfigs() } LaunchedEffect(Unit) { getConfigs() }
MyScaffold(R.string.override_apn, onNavigateUp, 0.dp) { MyScaffold(R.string.override_apn, onNavigateUp, 0.dp) {
@@ -1859,30 +1877,30 @@ fun AddApnSettingScreen(
) { ) {
val context = LocalContext.current val context = LocalContext.current
var menu by remember { mutableStateOf(ApnMenu.None) } var menu by remember { mutableStateOf(ApnMenu.None) }
var enabled by remember { mutableStateOf(true) } var enabled by rememberSaveable { mutableStateOf(true) }
var entryName by remember { mutableStateOf(origin?.name ?: "") } var entryName by rememberSaveable { mutableStateOf(origin?.name ?: "") }
var apnName by remember { mutableStateOf(origin?.apn ?: "") } var apnName by rememberSaveable { mutableStateOf(origin?.apn ?: "") }
var apnType by remember { mutableIntStateOf(origin?.apnType ?: 0) } var apnType by rememberSaveable { mutableIntStateOf(origin?.apnType ?: 0) }
var profileId by remember { mutableStateOf(origin?.profileId?.toString() ?: "") } var profileId by rememberSaveable { mutableStateOf(origin?.profileId?.toString() ?: "") }
var carrierId by remember { mutableStateOf(origin?.carrierId?.toString() ?: "") } var carrierId by rememberSaveable { mutableStateOf(origin?.carrierId?.toString() ?: "") }
var authType by remember { mutableStateOf(ApnAuthType.None) } var authType by rememberSaveable { mutableStateOf(ApnAuthType.None) }
var user by remember { mutableStateOf(origin?.username ?: "") } var user by rememberSaveable { mutableStateOf(origin?.username ?: "") }
var password by remember { mutableStateOf(origin?.password ?: "") } var password by rememberSaveable { mutableStateOf(origin?.password ?: "") }
var proxy by remember { mutableStateOf(origin?.proxy ?: "") } var proxy by rememberSaveable { mutableStateOf(origin?.proxy ?: "") }
var port by remember { mutableStateOf(origin?.port?.toString() ?: "") } var port by rememberSaveable { mutableStateOf(origin?.port?.toString() ?: "") }
var mmsProxy by remember { mutableStateOf(origin?.mmsProxy ?: "") } var mmsProxy by rememberSaveable { mutableStateOf(origin?.mmsProxy ?: "") }
var mmsPort by remember { mutableStateOf(origin?.mmsPort?.toString() ?: "") } var mmsPort by rememberSaveable { mutableStateOf(origin?.mmsPort?.toString() ?: "") }
var mmsc by remember { mutableStateOf(origin?.mmsc ?: "") } var mmsc by rememberSaveable { mutableStateOf(origin?.mmsc ?: "") }
var mtuV4 by remember { mutableStateOf(origin?.mtuV4?.toString() ?: "") } var mtuV4 by rememberSaveable { mutableStateOf(origin?.mtuV4?.toString() ?: "") }
var mtuV6 by remember { mutableStateOf(origin?.mtuV6?.toString() ?: "") } var mtuV6 by rememberSaveable { mutableStateOf(origin?.mtuV6?.toString() ?: "") }
var mvnoType by remember { mutableStateOf(origin?.mvno ?: ApnMvnoType.SPN) } var mvnoType by rememberSaveable { mutableStateOf(origin?.mvno ?: ApnMvnoType.SPN) }
var networkType by remember { mutableIntStateOf(origin?.networkType ?: 0) } var networkType by rememberSaveable { mutableIntStateOf(origin?.networkType ?: 0) }
var operatorNumeric by remember { mutableStateOf(origin?.operatorNumeric ?: "") } var operatorNumeric by rememberSaveable { mutableStateOf(origin?.operatorNumeric ?: "") }
var protocol by remember { mutableStateOf(origin?.protocol ?: ApnProtocol.Ip) } var protocol by rememberSaveable { mutableStateOf(origin?.protocol ?: ApnProtocol.Ip) }
var roamingProtocol by remember { mutableStateOf(origin?.roamingProtocol ?: ApnProtocol.Ip) } var roamingProtocol by rememberSaveable { mutableStateOf(origin?.roamingProtocol ?: ApnProtocol.Ip) }
var persistent by remember { mutableStateOf(origin?.persistent == true) } var persistent by rememberSaveable { mutableStateOf(origin?.persistent == true) }
var alwaysOn by remember { mutableStateOf(origin?.alwaysOn == true) } var alwaysOn by rememberSaveable { mutableStateOf(origin?.alwaysOn == true) }
var errorMessage: String? by remember { mutableStateOf(null) } var errorMessage: String? by rememberSaveable { mutableStateOf(null) }
MySmallTitleScaffold(R.string.apn_setting, onNavigateUp) { MySmallTitleScaffold(R.string.apn_setting, onNavigateUp) {
SwitchItem(R.string.enabled, state = enabled, onCheckedChange = { enabled = it }, padding = false) SwitchItem(R.string.enabled, state = enabled, onCheckedChange = { enabled = it }, padding = false)
OutlinedTextField( OutlinedTextField(
@@ -1950,7 +1968,7 @@ fun AddApnSettingScreen(
OutlinedTextField( OutlinedTextField(
authType.text, {}, Modifier.fillMaxWidth(), authType.text, {}, Modifier.fillMaxWidth(),
label = { Text("Authentication type") }, label = { Text("Authentication type") },
trailingIcon = { ExpandExposedTextFieldIcon(menu == ApnMenu.AuthType) } trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(menu == ApnMenu.AuthType) }
) )
ExposedDropdownMenu(menu == ApnMenu.AuthType, { menu = ApnMenu.None }) { ExposedDropdownMenu(menu == ApnMenu.AuthType, { menu = ApnMenu.None }) {
ApnAuthType.entries.forEach { ApnAuthType.entries.forEach {
@@ -1970,7 +1988,7 @@ fun AddApnSettingScreen(
OutlinedTextField( OutlinedTextField(
protocol.text, {}, Modifier.fillMaxWidth(), protocol.text, {}, Modifier.fillMaxWidth(),
label = { Text("APN protocol") }, label = { Text("APN protocol") },
trailingIcon = { ExpandExposedTextFieldIcon(menu == ApnMenu.Protocol) } trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(menu == ApnMenu.Protocol) }
) )
ExposedDropdownMenu(menu == ApnMenu.Protocol, { menu = ApnMenu.None }) { ExposedDropdownMenu(menu == ApnMenu.Protocol, { menu = ApnMenu.None }) {
ApnProtocol.entries.filter { VERSION.SDK_INT >= it.requiresApi }.forEach { ApnProtocol.entries.filter { VERSION.SDK_INT >= it.requiresApi }.forEach {
@@ -1991,7 +2009,9 @@ fun AddApnSettingScreen(
OutlinedTextField( OutlinedTextField(
roamingProtocol.text, {}, Modifier.fillMaxWidth(), roamingProtocol.text, {}, Modifier.fillMaxWidth(),
label = { Text("APN roaming protocol") }, label = { Text("APN roaming protocol") },
trailingIcon = { ExpandExposedTextFieldIcon(menu == ApnMenu.RoamingProtocol) } trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(menu == ApnMenu.RoamingProtocol)
}
) )
ExposedDropdownMenu(menu == ApnMenu.RoamingProtocol, { menu = ApnMenu.None }) { ExposedDropdownMenu(menu == ApnMenu.RoamingProtocol, { menu = ApnMenu.None }) {
ApnProtocol.entries.filter { VERSION.SDK_INT >= it.requiresApi }.forEach { ApnProtocol.entries.filter { VERSION.SDK_INT >= it.requiresApi }.forEach {
@@ -2050,7 +2070,9 @@ fun AddApnSettingScreen(
mvnoType.text, {}, mvnoType.text, {},
Modifier.fillMaxWidth().menuAnchor(MenuAnchorType.PrimaryNotEditable), Modifier.fillMaxWidth().menuAnchor(MenuAnchorType.PrimaryNotEditable),
readOnly = true, label = { Text("MVNO type") }, readOnly = true, label = { Text("MVNO type") },
trailingIcon = { ExpandExposedTextFieldIcon(menu == ApnMenu.RoamingProtocol) } trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(menu == ApnMenu.RoamingProtocol)
}
) )
ExposedDropdownMenu(menu == ApnMenu.MvnoType, { menu = ApnMenu.None }) { ExposedDropdownMenu(menu == ApnMenu.MvnoType, { menu = ApnMenu.None }) {
ApnMvnoType.entries.forEach { ApnMvnoType.entries.forEach {

View File

@@ -43,6 +43,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
@@ -80,7 +81,7 @@ import kotlinx.serialization.Serializable
fun PasswordScreen(vm: MyViewModel,onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) { fun PasswordScreen(vm: MyViewModel,onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
val context = LocalContext.current val context = LocalContext.current
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
var dialog by remember { mutableIntStateOf(0) } var dialog by rememberSaveable { mutableIntStateOf(0) }
MyScaffold(R.string.password_and_keyguard, onNavigateUp, 0.dp) { MyScaffold(R.string.password_and_keyguard, onNavigateUp, 0.dp) {
FunctionItem(R.string.password_info, icon = R.drawable.info_fill0) { onNavigate(PasswordInfo) } FunctionItem(R.string.password_info, icon = R.drawable.info_fill0) { onNavigate(PasswordInfo) }
if (SP.displayDangerousFeatures) { if (SP.displayDangerousFeatures) {
@@ -210,7 +211,7 @@ fun PasswordInfoScreen(
onNavigateUp: () -> Unit onNavigateUp: () -> Unit
) { ) {
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
var dialog by remember { mutableIntStateOf(0) } // 0:none, 1:password complexity var dialog by rememberSaveable { mutableIntStateOf(0) } // 0:none, 1:password complexity
MyScaffold(R.string.password_info, onNavigateUp, 0.dp) { MyScaffold(R.string.password_info, onNavigateUp, 0.dp) {
if (VERSION.SDK_INT >= 29) { if (VERSION.SDK_INT >= 29) {
InfoItem(R.string.current_password_complexity, getComplexity().text, true) { dialog = 1 } InfoItem(R.string.current_password_complexity, getComplexity().text, true) { dialog = 1 }
@@ -242,8 +243,8 @@ fun ResetPasswordTokenScreen(
clearToken: () -> Boolean, onNavigateUp: () -> Unit clearToken: () -> Boolean, onNavigateUp: () -> Unit
) { ) {
val context = LocalContext.current val context = LocalContext.current
var token by remember { mutableStateOf("") } var token by rememberSaveable { mutableStateOf("") }
var state by remember { mutableStateOf(getState()) } var state by rememberSaveable { mutableStateOf(getState()) }
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == Activity.RESULT_OK) { if (it.resultCode == Activity.RESULT_OK) {
context.popToast(R.string.token_activated) context.popToast(R.string.token_activated)
@@ -305,10 +306,10 @@ fun ResetPasswordTokenScreen(
@Composable @Composable
fun ResetPasswordScreen(resetPassword: (String, String, Int) -> Boolean, onNavigateUp: () -> Unit) { fun ResetPasswordScreen(resetPassword: (String, String, Int) -> Boolean, onNavigateUp: () -> Unit) {
val context = LocalContext.current val context = LocalContext.current
var password by remember { mutableStateOf("") } var password by rememberSaveable { mutableStateOf("") }
var token by remember { mutableStateOf("") } var token by rememberSaveable { mutableStateOf("") }
var flags by remember { mutableIntStateOf(0) } var flags by rememberSaveable { mutableIntStateOf(0) }
var confirmPassword by remember { mutableStateOf("") } var confirmPassword by rememberSaveable { mutableStateOf("") }
MyScaffold(R.string.reset_password, onNavigateUp) { MyScaffold(R.string.reset_password, onNavigateUp) {
if (VERSION.SDK_INT >= 26) { if (VERSION.SDK_INT >= 26) {
OutlinedTextField( OutlinedTextField(
@@ -366,7 +367,7 @@ fun RequiredPasswordComplexityScreen(
onNavigateUp: () -> Unit onNavigateUp: () -> Unit
) { ) {
val context = LocalContext.current val context = LocalContext.current
var complexity by remember { mutableStateOf(PasswordComplexity.None) } var complexity by rememberSaveable { mutableStateOf(PasswordComplexity.None) }
LaunchedEffect(Unit) { complexity = getComplexity() } LaunchedEffect(Unit) { complexity = getComplexity() }
MyScaffold(R.string.required_password_complexity, onNavigateUp, 0.dp) { MyScaffold(R.string.required_password_complexity, onNavigateUp, 0.dp) {
PasswordComplexity.entries.forEach { PasswordComplexity.entries.forEach {
@@ -415,8 +416,8 @@ fun KeyguardDisabledFeaturesScreen(
onNavigateUp: () -> Unit onNavigateUp: () -> Unit
) { ) {
val context = LocalContext.current val context = LocalContext.current
var mode by remember { mutableStateOf(KeyguardDisableMode.None) } var mode by rememberSaveable { mutableStateOf(KeyguardDisableMode.None) }
var flags by remember { mutableIntStateOf(0) } var flags by rememberSaveable { mutableIntStateOf(0) }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
val config = getConfig() val config = getConfig()
mode = config.mode mode = config.mode
@@ -462,7 +463,7 @@ fun RequiredPasswordQualityScreen(onNavigateUp: () -> Unit) {
PASSWORD_QUALITY_BIOMETRIC_WEAK to R.string.password_quality_biometrics_weak, PASSWORD_QUALITY_BIOMETRIC_WEAK to R.string.password_quality_biometrics_weak,
PASSWORD_QUALITY_NUMERIC_COMPLEX to R.string.password_quality_numeric_complex PASSWORD_QUALITY_NUMERIC_COMPLEX to R.string.password_quality_numeric_complex
) )
var selectedItem by remember { mutableIntStateOf(PASSWORD_QUALITY_UNSPECIFIED) } var selectedItem by rememberSaveable { mutableIntStateOf(PASSWORD_QUALITY_UNSPECIFIED) }
LaunchedEffect(Unit) { selectedItem = Privilege.DPM.getPasswordQuality(Privilege.DAR) } LaunchedEffect(Unit) { selectedItem = Privilege.DPM.getPasswordQuality(Privilege.DAR) }
MyScaffold(R.string.required_password_quality, onNavigateUp) { MyScaffold(R.string.required_password_quality, onNavigateUp) {
passwordQuality.forEach { passwordQuality.forEach {

View File

@@ -16,11 +16,9 @@ import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.FlowRow
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.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.ime
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
@@ -90,6 +88,7 @@ import com.bintianqi.owndroid.MyViewModel
import com.bintianqi.owndroid.Privilege import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.Settings import com.bintianqi.owndroid.Settings
import com.bintianqi.owndroid.adaptiveInsets
import com.bintianqi.owndroid.showOperationResultToast import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.CircularProgressDialog import com.bintianqi.owndroid.ui.CircularProgressDialog
import com.bintianqi.owndroid.ui.InfoItem import com.bintianqi.owndroid.ui.InfoItem
@@ -116,9 +115,9 @@ fun WorkModesScreen(
) { ) {
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
/** 0: none, 1: device owner, 2: circular progress indicator, 3: result, 4: deactivate, 5: command */ /** 0: none, 1: device owner, 2: circular progress indicator, 3: result, 4: deactivate, 5: command */
var dialog by remember { mutableIntStateOf(0) } var dialog by rememberSaveable { mutableIntStateOf(0) }
var operationSucceed by remember { mutableStateOf(false) } var operationSucceed by rememberSaveable { mutableStateOf(false) }
var resultText by remember { mutableStateOf("") } var resultText by rememberSaveable { mutableStateOf("") }
LaunchedEffect(privilege) { LaunchedEffect(privilege) {
if (!params.canNavigateUp && privilege.device) { if (!params.canNavigateUp && privilege.device) {
delay(1000) delay(1000)
@@ -182,7 +181,7 @@ fun WorkModesScreen(
} }
) )
}, },
contentWindowInsets = WindowInsets.ime contentWindowInsets = adaptiveInsets()
) { paddingValues -> ) { paddingValues ->
fun handleResult(succeeded: Boolean, output: String?) { fun handleResult(succeeded: Boolean, output: String?) {
operationSucceed = succeeded operationSucceed = succeeded
@@ -367,7 +366,7 @@ fun DhizukuServerSettingsScreen(
getDhizukuClients: () -> Unit, updateDhizukuClient: (DhizukuClientInfo) -> Unit, getDhizukuClients: () -> Unit, updateDhizukuClient: (DhizukuClientInfo) -> Unit,
getServerEnabled: () -> Boolean, setServerEnabled: (Boolean) -> Unit, onNavigateUp: () -> Unit getServerEnabled: () -> Boolean, setServerEnabled: (Boolean) -> Unit, onNavigateUp: () -> Unit
) { ) {
var enabled by remember { mutableStateOf(getServerEnabled()) } var enabled by rememberSaveable { mutableStateOf(getServerEnabled()) }
val clients by dhizukuClients.collectAsStateWithLifecycle() val clients by dhizukuClients.collectAsStateWithLifecycle()
LaunchedEffect(Unit) { getDhizukuClients() } LaunchedEffect(Unit) { getDhizukuClients() }
MyLazyScaffold(R.string.dhizuku_server, onNavigateUp) { MyLazyScaffold(R.string.dhizuku_server, onNavigateUp) {
@@ -455,7 +454,7 @@ fun LockScreenInfoScreen(
) { ) {
val context = LocalContext.current val context = LocalContext.current
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var infoText by remember { mutableStateOf(getText()) } var infoText by rememberSaveable { mutableStateOf(getText()) }
MyScaffold(R.string.lock_screen_info, onNavigateUp) { MyScaffold(R.string.lock_screen_info, onNavigateUp) {
OutlinedTextField( OutlinedTextField(
value = infoText, value = infoText,
@@ -566,7 +565,7 @@ fun AddDelegatedAdminScreen(
setDelegatedAdmin: (String, List<String>) -> Unit, onNavigateUp: () -> Unit setDelegatedAdmin: (String, List<String>) -> Unit, onNavigateUp: () -> Unit
) { ) {
val updateMode = data.pkg.isNotEmpty() val updateMode = data.pkg.isNotEmpty()
var input by remember { mutableStateOf(data.pkg) } var input by rememberSaveable { mutableStateOf(data.pkg) }
val scopes = rememberSaveable { mutableStateListOf(*data.scopes.toTypedArray()) } val scopes = rememberSaveable { mutableStateListOf(*data.scopes.toTypedArray()) }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
input = chosenPackage.receive() input = chosenPackage.receive()
@@ -625,7 +624,7 @@ fun AddDelegatedAdminScreen(
@Composable @Composable
fun DeviceInfoScreen(vm: MyViewModel, onNavigateUp: () -> Unit) { fun DeviceInfoScreen(vm: MyViewModel, onNavigateUp: () -> Unit) {
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
var dialog by remember { mutableIntStateOf(0) } var dialog by rememberSaveable { mutableIntStateOf(0) }
MyScaffold(R.string.device_info, onNavigateUp, 0.dp) { MyScaffold(R.string.device_info, onNavigateUp, 0.dp) {
if (VERSION.SDK_INT >= 34 && (privilege.device || privilege.org)) { if (VERSION.SDK_INT >= 34 && (privilege.device || privilege.org)) {
InfoItem(R.string.financed_device, vm.getDeviceFinanced().yesOrNo) InfoItem(R.string.financed_device, vm.getDeviceFinanced().yesOrNo)
@@ -666,8 +665,8 @@ fun SupportMessageScreen(
setLongMessage: (String?) -> Unit, onNavigateUp: () -> Unit setLongMessage: (String?) -> Unit, onNavigateUp: () -> Unit
) { ) {
val context = LocalContext.current val context = LocalContext.current
var shortMsg by remember { mutableStateOf("") } var shortMsg by rememberSaveable { mutableStateOf("") }
var longMsg by remember { mutableStateOf("") } var longMsg by rememberSaveable { mutableStateOf("") }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
shortMsg = getShortMessage() shortMsg = getShortMessage()
longMsg = getLongMessage() longMsg = getLongMessage()
@@ -750,8 +749,8 @@ fun TransferOwnershipScreen(
transferOwnership: (ComponentName) -> Unit, onNavigateUp: () -> Unit, onTransferred: () -> Unit transferOwnership: (ComponentName) -> Unit, onNavigateUp: () -> Unit, onTransferred: () -> Unit
) { ) {
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
var selectedIndex by remember { mutableIntStateOf(-1) } var selectedIndex by rememberSaveable { mutableIntStateOf(-1) }
var dialog by remember { mutableStateOf(false) } var dialog by rememberSaveable { mutableStateOf(false) }
val receivers by deviceAdmins.collectAsStateWithLifecycle() val receivers by deviceAdmins.collectAsStateWithLifecycle()
LaunchedEffect(Unit) { getDeviceAdmins() } LaunchedEffect(Unit) { getDeviceAdmins() }
MyLazyScaffold(R.string.transfer_ownership, onNavigateUp) { MyLazyScaffold(R.string.transfer_ownership, onNavigateUp) {

View File

@@ -31,17 +31,13 @@ import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
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.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.ime
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
@@ -110,7 +106,9 @@ import com.bintianqi.owndroid.MyViewModel
import com.bintianqi.owndroid.Privilege import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.SP import com.bintianqi.owndroid.SP
import com.bintianqi.owndroid.clickableTextField
import com.bintianqi.owndroid.formatDate import com.bintianqi.owndroid.formatDate
import com.bintianqi.owndroid.adaptiveInsets
import com.bintianqi.owndroid.popToast import com.bintianqi.owndroid.popToast
import com.bintianqi.owndroid.showOperationResultToast import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.CheckBoxItem import com.bintianqi.owndroid.ui.CheckBoxItem
@@ -146,7 +144,7 @@ fun SystemManagerScreen(
val context = LocalContext.current val context = LocalContext.current
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
/** 1: reboot, 2: bug report, 3: org name, 4: org id, 5: enrollment specific id*/ /** 1: reboot, 2: bug report, 3: org name, 4: org id, 5: enrollment specific id*/
var dialog by remember { mutableIntStateOf(0) } var dialog by rememberSaveable { mutableIntStateOf(0) }
MyScaffold(R.string.system, onNavigateUp, 0.dp) { MyScaffold(R.string.system, onNavigateUp, 0.dp) {
FunctionItem(R.string.options, icon = R.drawable.tune_fill0) { onNavigate(SystemOptions) } FunctionItem(R.string.options, icon = R.drawable.tune_fill0) { onNavigate(SystemOptions) }
FunctionItem(R.string.keyguard, icon = R.drawable.screen_lock_portrait_fill0) { onNavigate(Keyguard) } FunctionItem(R.string.keyguard, icon = R.drawable.screen_lock_portrait_fill0) { onNavigate(Keyguard) }
@@ -242,7 +240,7 @@ fun SystemManagerScreen(
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) )
if(dialog in 3..5) { if(dialog in 3..5) {
var input by remember { mutableStateOf("") } var input by rememberSaveable { mutableStateOf("") }
AlertDialog( AlertDialog(
text = { text = {
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
@@ -323,7 +321,7 @@ data class SystemOptionsStatus(
@Composable @Composable
fun SystemOptionsScreen(vm: MyViewModel, onNavigateUp: () -> Unit) { fun SystemOptionsScreen(vm: MyViewModel, onNavigateUp: () -> Unit) {
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
var dialog by remember { mutableIntStateOf(0) } var dialog by rememberSaveable { mutableIntStateOf(0) }
val status by vm.systemOptionsStatus.collectAsStateWithLifecycle() val status by vm.systemOptionsStatus.collectAsStateWithLifecycle()
LaunchedEffect(Unit) { vm.getSystemOptionsStatus() } LaunchedEffect(Unit) { vm.getSystemOptionsStatus() }
MyScaffold(R.string.options, onNavigateUp, 0.dp) { MyScaffold(R.string.options, onNavigateUp, 0.dp) {
@@ -436,7 +434,7 @@ fun KeyguardScreen(
} }
if(VERSION.SDK_INT >= 23) Text(text = stringResource(R.string.lock_now), style = typography.headlineLarge) if(VERSION.SDK_INT >= 23) Text(text = stringResource(R.string.lock_now), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 2.dp)) Spacer(Modifier.padding(vertical = 2.dp))
var evictKey by remember { mutableStateOf(false) } var evictKey by rememberSaveable { mutableStateOf(false) }
Button( Button(
onClick = { lock(evictKey) }, onClick = { lock(evictKey) },
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
@@ -475,7 +473,7 @@ fun HardwareMonitorScreen(
onNavigateUp: () -> Unit onNavigateUp: () -> Unit
) { ) {
val properties by hardwareProperties.collectAsStateWithLifecycle() val properties by hardwareProperties.collectAsStateWithLifecycle()
var refreshInterval by remember { mutableFloatStateOf(1F) } var refreshInterval by rememberSaveable { mutableFloatStateOf(1F) }
val refreshIntervalMs = (refreshInterval * 1000).roundToLong() val refreshIntervalMs = (refreshInterval * 1000).roundToLong()
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
getHardwareProperties() getHardwareProperties()
@@ -540,18 +538,14 @@ fun HardwareMonitorScreen(
fun ChangeTimeScreen(setTime: (Long, Boolean) -> Boolean, onNavigateUp: () -> Unit) { fun ChangeTimeScreen(setTime: (Long, Boolean) -> Boolean, onNavigateUp: () -> Unit) {
val context = LocalContext.current val context = LocalContext.current
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var tab by remember { mutableIntStateOf(0) } var tab by rememberSaveable { mutableIntStateOf(0) }
val pagerState = rememberPagerState { 2 } val pagerState = rememberPagerState { 2 }
tab = pagerState.currentPage tab = pagerState.currentPage
val coroutine = rememberCoroutineScope() val coroutine = rememberCoroutineScope()
var picker by remember { mutableIntStateOf(0) } //0:None, 1:DatePicker, 2:TimePicker var picker by rememberSaveable { mutableIntStateOf(0) } //0:None, 1:DatePicker, 2:TimePicker
var useCurrentTz by remember { mutableStateOf(true) } var useCurrentTz by rememberSaveable { mutableStateOf(true) }
val datePickerState = rememberDatePickerState() val datePickerState = rememberDatePickerState()
val timePickerState = rememberTimePickerState(is24Hour = true) val timePickerState = rememberTimePickerState(is24Hour = true)
val dateInteractionSource = remember { MutableInteractionSource() }
val timeInteractionSource = remember { MutableInteractionSource() }
if(dateInteractionSource.collectIsPressedAsState().value) picker = 1
if(timeInteractionSource.collectIsPressedAsState().value) picker = 2
Scaffold( Scaffold(
topBar = { topBar = {
TopAppBar( TopAppBar(
@@ -560,7 +554,7 @@ fun ChangeTimeScreen(setTime: (Long, Boolean) -> Boolean, onNavigateUp: () -> Un
colors = TopAppBarDefaults.topAppBarColors(colorScheme.surfaceContainer) colors = TopAppBarDefaults.topAppBarColors(colorScheme.surfaceContainer)
) )
}, },
contentWindowInsets = WindowInsets.ime contentWindowInsets = adaptiveInsets()
) { paddingValues -> ) { paddingValues ->
Column( Column(
Modifier Modifier
@@ -592,17 +586,16 @@ fun ChangeTimeScreen(setTime: (Long, Boolean) -> Boolean, onNavigateUp: () -> Un
value = datePickerState.selectedDateMillis?.let { formatDate(it) } ?: "", value = datePickerState.selectedDateMillis?.let { formatDate(it) } ?: "",
onValueChange = {}, readOnly = true, onValueChange = {}, readOnly = true,
label = { Text(stringResource(R.string.date)) }, label = { Text(stringResource(R.string.date)) },
interactionSource = dateInteractionSource, modifier = Modifier.fillMaxWidth().clickableTextField { picker = 1 }
modifier = Modifier.fillMaxWidth()
) )
OutlinedTextField( OutlinedTextField(
value = timePickerState.hour.toString().padStart(2, '0') + ":" + value = timePickerState.hour.toString().padStart(2, '0') + ":" +
timePickerState.minute.toString().padStart(2, '0'), timePickerState.minute.toString().padStart(2, '0'),
onValueChange = {}, readOnly = true, onValueChange = {}, readOnly = true,
label = { Text(stringResource(R.string.time)) }, label = { Text(stringResource(R.string.time)) },
interactionSource = timeInteractionSource,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clickableTextField { picker = 2 }
.padding(vertical = 4.dp) .padding(vertical = 4.dp)
) )
CheckBoxItem(R.string.use_current_timezone, useCurrentTz) { CheckBoxItem(R.string.use_current_timezone, useCurrentTz) {
@@ -620,13 +613,12 @@ fun ChangeTimeScreen(setTime: (Long, Boolean) -> Boolean, onNavigateUp: () -> Un
Text(stringResource(R.string.apply)) Text(stringResource(R.string.apply))
} }
} else { } else {
var inputTime by remember { mutableStateOf("") } var inputTime by rememberSaveable { mutableStateOf("") }
OutlinedTextField( OutlinedTextField(
value = inputTime, value = inputTime,
label = { Text(stringResource(R.string.time_unit_ms)) }, label = { Text(stringResource(R.string.time_unit_ms)) },
onValueChange = { inputTime = it }, onValueChange = { inputTime = it },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) )
Button( Button(
@@ -673,8 +665,8 @@ fun ChangeTimeScreen(setTime: (Long, Boolean) -> Boolean, onNavigateUp: () -> Un
fun ChangeTimeZoneScreen(setTimeZone: (String) -> Boolean, onNavigateUp: () -> Unit) { fun ChangeTimeZoneScreen(setTimeZone: (String) -> Boolean, onNavigateUp: () -> Unit) {
val context = LocalContext.current val context = LocalContext.current
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var inputTimezone by remember { mutableStateOf("") } var inputTimezone by rememberSaveable { mutableStateOf("") }
var dialog by remember { mutableStateOf(false) } var dialog by rememberSaveable { mutableStateOf(false) }
val availableIds = TimeZone.getAvailableIDs() val availableIds = TimeZone.getAvailableIDs()
val validInput = inputTimezone in availableIds val validInput = inputTimezone in availableIds
MyScaffold(R.string.change_timezone, onNavigateUp) { MyScaffold(R.string.change_timezone, onNavigateUp) {
@@ -741,7 +733,7 @@ fun AutoTimePolicyScreen(
getPolicy: () -> Int, setPolicy: (Int) -> Unit, onNavigateUp: () -> Unit getPolicy: () -> Int, setPolicy: (Int) -> Unit, onNavigateUp: () -> Unit
) = MyScaffold(R.string.auto_time_policy, onNavigateUp, 0.dp) { ) = MyScaffold(R.string.auto_time_policy, onNavigateUp, 0.dp) {
val context = LocalContext.current val context = LocalContext.current
var policy by remember { mutableIntStateOf(getPolicy()) } var policy by rememberSaveable { mutableIntStateOf(getPolicy()) }
listOf( listOf(
DevicePolicyManager.AUTO_TIME_ENABLED to R.string.enable, DevicePolicyManager.AUTO_TIME_ENABLED to R.string.enable,
DevicePolicyManager.AUTO_TIME_DISABLED to R.string.disabled, DevicePolicyManager.AUTO_TIME_DISABLED to R.string.disabled,
@@ -772,7 +764,7 @@ fun AutoTimeZonePolicyScreen(
getPolicy: () -> Int, setPolicy: (Int) -> Unit, onNavigateUp: () -> Unit getPolicy: () -> Int, setPolicy: (Int) -> Unit, onNavigateUp: () -> Unit
) = MyScaffold(R.string.auto_timezone_policy, onNavigateUp, 0.dp) { ) = MyScaffold(R.string.auto_timezone_policy, onNavigateUp, 0.dp) {
val context = LocalContext.current val context = LocalContext.current
var policy by remember { mutableIntStateOf(getPolicy()) } var policy by rememberSaveable { mutableIntStateOf(getPolicy()) }
listOf( listOf(
DevicePolicyManager.AUTO_TIME_ZONE_ENABLED to R.string.enable, DevicePolicyManager.AUTO_TIME_ZONE_ENABLED to R.string.enable,
DevicePolicyManager.AUTO_TIME_ZONE_DISABLED to R.string.disabled, DevicePolicyManager.AUTO_TIME_ZONE_DISABLED to R.string.disabled,
@@ -980,7 +972,7 @@ fun ContentProtectionPolicyScreen(
getPolicy: () -> Int, setPolicy: (Int) -> Unit, onNavigateUp: () -> Unit getPolicy: () -> Int, setPolicy: (Int) -> Unit, onNavigateUp: () -> Unit
) { ) {
val context = LocalContext.current val context = LocalContext.current
var policy by remember { mutableIntStateOf(getPolicy()) } var policy by rememberSaveable { mutableIntStateOf(getPolicy()) }
MyScaffold(R.string.content_protection_policy, onNavigateUp, 0.dp) { MyScaffold(R.string.content_protection_policy, onNavigateUp, 0.dp) {
mapOf( mapOf(
DevicePolicyManager.CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY to R.string.not_controlled_by_policy, DevicePolicyManager.CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY to R.string.not_controlled_by_policy,
@@ -1012,7 +1004,7 @@ fun PermissionPolicyScreen(
getPolicy: () -> Int, setPolicy: (Int) -> Unit, onNavigateUp: () -> Unit getPolicy: () -> Int, setPolicy: (Int) -> Unit, onNavigateUp: () -> Unit
) { ) {
val context = LocalContext.current val context = LocalContext.current
var selectedPolicy by remember { mutableIntStateOf(getPolicy()) } var selectedPolicy by rememberSaveable { mutableIntStateOf(getPolicy()) }
MyScaffold(R.string.permission_policy, onNavigateUp, 0.dp) { MyScaffold(R.string.permission_policy, onNavigateUp, 0.dp) {
FullWidthRadioButtonItem(R.string.default_stringres, selectedPolicy == PERMISSION_POLICY_PROMPT) { FullWidthRadioButtonItem(R.string.default_stringres, selectedPolicy == PERMISSION_POLICY_PROMPT) {
selectedPolicy = PERMISSION_POLICY_PROMPT selectedPolicy = PERMISSION_POLICY_PROMPT
@@ -1045,7 +1037,7 @@ fun PermissionPolicyScreen(
fun MtePolicyScreen( fun MtePolicyScreen(
getPolicy: () -> Int, setPolicy: (Int) -> Boolean, onNavigateUp: () -> Unit getPolicy: () -> Int, setPolicy: (Int) -> Boolean, onNavigateUp: () -> Unit
) { ) {
var policy by remember { mutableIntStateOf(getPolicy()) } var policy by rememberSaveable { mutableIntStateOf(getPolicy()) }
MyScaffold(R.string.mte_policy, onNavigateUp, 0.dp) { MyScaffold(R.string.mte_policy, onNavigateUp, 0.dp) {
FullWidthRadioButtonItem(R.string.decide_by_user, policy == MTE_NOT_CONTROLLED_BY_POLICY) { FullWidthRadioButtonItem(R.string.decide_by_user, policy == MTE_NOT_CONTROLLED_BY_POLICY) {
policy = MTE_NOT_CONTROLLED_BY_POLICY policy = MTE_NOT_CONTROLLED_BY_POLICY
@@ -1075,7 +1067,7 @@ fun NearbyStreamingPolicyScreen(
setNotificationPolicy: (Int) -> Unit, onNavigateUp: () -> Unit setNotificationPolicy: (Int) -> Unit, onNavigateUp: () -> Unit
) { ) {
val context = LocalContext.current val context = LocalContext.current
var appPolicy by remember { mutableIntStateOf(getAppPolicy()) } var appPolicy by rememberSaveable { mutableIntStateOf(getAppPolicy()) }
MySmallTitleScaffold(R.string.nearby_streaming_policy, onNavigateUp, 0.dp) { MySmallTitleScaffold(R.string.nearby_streaming_policy, onNavigateUp, 0.dp) {
Text( Text(
stringResource(R.string.nearby_app_streaming), stringResource(R.string.nearby_app_streaming),
@@ -1104,7 +1096,7 @@ fun NearbyStreamingPolicyScreen(
} }
Notes(R.string.info_nearby_app_streaming_policy, HorizontalPadding) Notes(R.string.info_nearby_app_streaming_policy, HorizontalPadding)
Spacer(Modifier.height(20.dp)) Spacer(Modifier.height(20.dp))
var notificationPolicy by remember { mutableIntStateOf(getNotificationPolicy()) } var notificationPolicy by rememberSaveable { mutableIntStateOf(getNotificationPolicy()) }
Text( Text(
stringResource(R.string.nearby_notification_streaming), stringResource(R.string.nearby_notification_streaming),
Modifier.padding(start = 8.dp, top = 10.dp, bottom = 4.dp), style = typography.titleLarge Modifier.padding(start = 8.dp, top = 10.dp, bottom = 4.dp), style = typography.titleLarge
@@ -1153,7 +1145,7 @@ fun LockTaskModeScreen(
) { ) {
val coroutine = rememberCoroutineScope() val coroutine = rememberCoroutineScope()
val pagerState = rememberPagerState { 3 } val pagerState = rememberPagerState { 3 }
var tabIndex by remember { mutableIntStateOf(0) } var tabIndex by rememberSaveable { mutableIntStateOf(0) }
tabIndex = pagerState.targetPage tabIndex = pagerState.targetPage
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
getLockTaskPackages() getLockTaskPackages()
@@ -1166,7 +1158,7 @@ fun LockTaskModeScreen(
colors = TopAppBarDefaults.topAppBarColors(colorScheme.surfaceContainer) colors = TopAppBarDefaults.topAppBarColors(colorScheme.surfaceContainer)
) )
}, },
contentWindowInsets = WindowInsets.ime contentWindowInsets = adaptiveInsets()
) { paddingValues -> ) { paddingValues ->
Column( Column(
modifier = Modifier modifier = Modifier
@@ -1301,8 +1293,8 @@ private fun LockTaskFeatures(
getLockTaskFeatures: () -> Int, setLockTaskFeature: (Int) -> String? getLockTaskFeatures: () -> Int, setLockTaskFeature: (Int) -> String?
) { ) {
val context = LocalContext.current val context = LocalContext.current
var flags by remember { mutableIntStateOf(getLockTaskFeatures()) } var flags by rememberSaveable { mutableIntStateOf(getLockTaskFeatures()) }
var errorMessage by remember { mutableStateOf<String?>(null) } var errorMessage by rememberSaveable { mutableStateOf<String?>(null) }
Column( Column(
Modifier Modifier
.fillMaxWidth() .fillMaxWidth()
@@ -1366,9 +1358,9 @@ fun CaCertScreen(
) { ) {
val context = LocalContext.current val context = LocalContext.current
/** 0:none, 1:install, 2:info, 3:uninstall all */ /** 0:none, 1:install, 2:info, 3:uninstall all */
var dialog by remember { mutableIntStateOf(0) } var dialog by rememberSaveable { mutableIntStateOf(0) }
val caCerts by caCertificates.collectAsStateWithLifecycle() val caCerts by caCertificates.collectAsStateWithLifecycle()
var selectedCaCert by remember { mutableStateOf<CaCertInfo?>(null) } var selectedCaCert by rememberSaveable { mutableStateOf<CaCertInfo?>(null) }
val getCertLauncher = rememberLauncherForActivityResult( val getCertLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.OpenDocument()) { uri -> ActivityResultContracts.OpenDocument()) { uri ->
if(uri != null) { if(uri != null) {
@@ -1400,7 +1392,8 @@ fun CaCertScreen(
}) { }) {
Icon(Icons.Default.Add, stringResource(R.string.install)) Icon(Icons.Default.Add, stringResource(R.string.install))
} }
} },
contentWindowInsets = adaptiveInsets()
) { paddingValues -> ) { paddingValues ->
LazyColumn( LazyColumn(
Modifier Modifier
@@ -1534,14 +1527,10 @@ fun SecurityLoggingScreen(
exportPRLogs: (Uri, () -> Unit) -> Unit, onNavigateUp: () -> Unit exportPRLogs: (Uri, () -> Unit) -> Unit, onNavigateUp: () -> Unit
) { ) {
val context = LocalContext.current val context = LocalContext.current
var enabled by remember { mutableStateOf(false) } var enabled by rememberSaveable { mutableStateOf(getEnabled()) }
var logsCount by remember { mutableIntStateOf(0) } var logsCount by rememberSaveable { mutableIntStateOf(getCount()) }
var exporting by remember { mutableStateOf(false) } var exporting by rememberSaveable { mutableStateOf(false) }
var dialog by remember { mutableStateOf(false) } var dialog by rememberSaveable { mutableStateOf(false) }
LaunchedEffect(Unit) {
enabled = getEnabled()
logsCount = getCount()
}
val exportLauncher = rememberLauncherForActivityResult( val exportLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.CreateDocument("application/json") ActivityResultContracts.CreateDocument("application/json")
) { ) {
@@ -1686,24 +1675,16 @@ data class FrpPolicyInfo(
@RequiresApi(30) @RequiresApi(30)
@Composable @Composable
fun FrpPolicyScreen( fun FrpPolicyScreen(
getFrpPolicy: () -> FrpPolicyInfo, setFrpPolicy: (FrpPolicyInfo) -> Unit, frpPolicy: FrpPolicyInfo, setFrpPolicy: (FrpPolicyInfo) -> Unit,
onNavigateUp: () -> Unit onNavigateUp: () -> Unit
) { ) {
val context = LocalContext.current
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var usePolicy by remember { mutableStateOf(false) } var usePolicy by rememberSaveable { mutableStateOf(frpPolicy.usePolicy) }
var enabled by remember { mutableStateOf(false) } var enabled by rememberSaveable { mutableStateOf(frpPolicy.enabled) }
var supported by remember { mutableStateOf(false) } var supported by rememberSaveable { mutableStateOf(frpPolicy.supported) }
val accountList = remember { mutableStateListOf<String>() } val accountList = rememberSaveable { mutableStateListOf(*frpPolicy.accounts.toTypedArray()) }
var inputAccount by remember { mutableStateOf("") } var inputAccount by rememberSaveable { mutableStateOf("") }
LaunchedEffect(Unit) {
val info = getFrpPolicy()
supported = info.supported
if (info.supported) {
usePolicy = info.usePolicy
enabled = info.enabled
accountList.addAll(info.accounts)
}
}
MyScaffold(R.string.frp_policy, onNavigateUp, 0.dp) { MyScaffold(R.string.frp_policy, onNavigateUp, 0.dp) {
if (!supported) { if (!supported) {
Column( Column(
@@ -1751,6 +1732,7 @@ fun FrpPolicyScreen(
onClick = { onClick = {
focusMgr.clearFocus() focusMgr.clearFocus()
setFrpPolicy(FrpPolicyInfo(true, usePolicy, enabled, accountList)) setFrpPolicy(FrpPolicyInfo(true, usePolicy, enabled, accountList))
context.showOperationResultToast(true)
}, },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@@ -1774,9 +1756,9 @@ fun WipeDataScreen(
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var flag by remember { mutableIntStateOf(WIPE_SILENTLY) } var flag by rememberSaveable { mutableIntStateOf(0) }
var dialog by remember { mutableIntStateOf(0) } // 0: none, 1: wipe data, 2: wipe device var dialog by rememberSaveable { mutableIntStateOf(0) } // 0: none, 1: wipe data, 2: wipe device
var reason by remember { mutableStateOf("") } var reason by rememberSaveable { mutableStateOf("") }
MyScaffold(R.string.wipe_data, onNavigateUp, 0.dp) { MyScaffold(R.string.wipe_data, onNavigateUp, 0.dp) {
FullWidthCheckBoxItem(R.string.wipe_external_storage, flag and WIPE_EXTERNAL_STORAGE != 0) { FullWidthCheckBoxItem(R.string.wipe_external_storage, flag and WIPE_EXTERNAL_STORAGE != 0) {
flag = flag xor WIPE_EXTERNAL_STORAGE flag = flag xor WIPE_EXTERNAL_STORAGE
@@ -1978,8 +1960,8 @@ fun InstallSystemUpdateScreen(
installSystemUpdate: (Uri, (String) -> Unit) -> Unit, onNavigateUp: () -> Unit installSystemUpdate: (Uri, (String) -> Unit) -> Unit, onNavigateUp: () -> Unit
) { ) {
var uri by remember { mutableStateOf<Uri?>(null) } var uri by remember { mutableStateOf<Uri?>(null) }
var installing by remember { mutableStateOf(false) } var installing by rememberSaveable { mutableStateOf(false) }
var errorMessage by remember { mutableStateOf<String?>(null) } var errorMessage by rememberSaveable { mutableStateOf<String?>(null) }
val getFileLauncher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri = it } val getFileLauncher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri = it }
MyScaffold(R.string.install_system_update, onNavigateUp) { MyScaffold(R.string.install_system_update, onNavigateUp) {
Button( Button(

View File

@@ -7,11 +7,9 @@ import androidx.compose.foundation.layout.Arrangement
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.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.ime
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
@@ -41,7 +39,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@@ -53,11 +51,13 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bintianqi.owndroid.BottomPadding
import com.bintianqi.owndroid.HorizontalPadding import com.bintianqi.owndroid.HorizontalPadding
import com.bintianqi.owndroid.Privilege import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.UserRestrictionCategory import com.bintianqi.owndroid.UserRestrictionCategory
import com.bintianqi.owndroid.UserRestrictionsRepository import com.bintianqi.owndroid.UserRestrictionsRepository
import com.bintianqi.owndroid.adaptiveInsets
import com.bintianqi.owndroid.popToast import com.bintianqi.owndroid.popToast
import com.bintianqi.owndroid.showOperationResultToast import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.FunctionItem import com.bintianqi.owndroid.ui.FunctionItem
@@ -99,7 +99,7 @@ fun UserRestrictionScreen(
scrollBehavior = sb scrollBehavior = sb
) )
}, },
contentWindowInsets = WindowInsets.ime contentWindowInsets = adaptiveInsets()
) { paddingValues -> ) { paddingValues ->
Column( Column(
modifier = Modifier modifier = Modifier
@@ -183,7 +183,7 @@ fun UserRestrictionOptionsScreen(
} }
} }
item { item {
Spacer(Modifier.padding(vertical = 30.dp)) Spacer(Modifier.height(BottomPadding))
} }
} }
} }
@@ -207,7 +207,7 @@ fun UserRestrictionEditorScreen(
navigationIcon = { NavIcon(onNavigateUp) } navigationIcon = { NavIcon(onNavigateUp) }
) )
}, },
contentWindowInsets = WindowInsets.ime contentWindowInsets = adaptiveInsets()
) { paddingValues -> ) { paddingValues ->
LazyColumn(Modifier.fillMaxSize().padding(paddingValues)) { LazyColumn(Modifier.fillMaxSize().padding(paddingValues)) {
items(list, { it }) { items(list, { it }) {
@@ -224,7 +224,7 @@ fun UserRestrictionEditorScreen(
} }
} }
item { item {
var input by remember { mutableStateOf("") } var input by rememberSaveable { mutableStateOf("") }
fun add() { fun add() {
if (!setRestriction(input, false)) context.showOperationResultToast(false) if (!setRestriction(input, false)) context.showOperationResultToast(false)
} }

View File

@@ -42,6 +42,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
@@ -81,7 +82,7 @@ fun UsersScreen(vm: MyViewModel, onNavigateUp: () -> Unit, onNavigate: (Any) ->
val context = LocalContext.current val context = LocalContext.current
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
/** 1: secondary users, 2: logout*/ /** 1: secondary users, 2: logout*/
var dialog by remember { mutableIntStateOf(0) } var dialog by rememberSaveable { mutableIntStateOf(0) }
MyScaffold(R.string.users, onNavigateUp, 0.dp) { MyScaffold(R.string.users, onNavigateUp, 0.dp) {
if(VERSION.SDK_INT >= 28 && privilege.profile && privilege.affiliated) { if(VERSION.SDK_INT >= 28 && privilege.profile && privilege.affiliated) {
FunctionItem(R.string.logout, icon = R.drawable.logout_fill0) { dialog = 2 } FunctionItem(R.string.logout, icon = R.drawable.logout_fill0) { dialog = 2 }
@@ -194,7 +195,7 @@ data class UserInformation(
@Composable @Composable
fun UserInfoScreen(getInfo: () -> UserInformation, onNavigateUp: () -> Unit) { fun UserInfoScreen(getInfo: () -> UserInformation, onNavigateUp: () -> Unit) {
var info by remember { mutableStateOf(UserInformation()) } var info by remember { mutableStateOf(UserInformation()) }
var infoDialog by remember { mutableIntStateOf(0) } var infoDialog by rememberSaveable { mutableIntStateOf(0) }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
info = getInfo() info = getInfo()
} }
@@ -234,10 +235,10 @@ fun UserOperationScreen(
stopUser: (Int, Boolean) -> Int, deleteUser: (Int, Boolean) -> Boolean, onNavigateUp: () -> Unit stopUser: (Int, Boolean) -> Int, deleteUser: (Int, Boolean) -> Boolean, onNavigateUp: () -> Unit
) { ) {
val context = LocalContext.current val context = LocalContext.current
var input by remember { mutableStateOf("") } var input by rememberSaveable { mutableStateOf("") }
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var useUserId by remember { mutableStateOf(false) } var useUserId by rememberSaveable { mutableStateOf(false) }
var dialog by remember { mutableStateOf(false) } var dialog by rememberSaveable { mutableStateOf(false) }
val legalInput = input.toIntOrNull() != null val legalInput = input.toIntOrNull() != null
MyScaffold(R.string.user_operation, onNavigateUp) { MyScaffold(R.string.user_operation, onNavigateUp) {
if(VERSION.SDK_INT >= 24) SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth()) { if(VERSION.SDK_INT >= 24) SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth()) {
@@ -335,9 +336,9 @@ fun CreateUserScreen(
) { ) {
var result by remember { mutableStateOf<CreateUserResult?>(null) } var result by remember { mutableStateOf<CreateUserResult?>(null) }
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var userName by remember { mutableStateOf("") } var userName by rememberSaveable { mutableStateOf("") }
var creating by remember { mutableStateOf(false) } var creating by rememberSaveable { mutableStateOf(false) }
var flags by remember { mutableIntStateOf(0) } var flags by rememberSaveable { mutableIntStateOf(0) }
MyScaffold(R.string.create_user, onNavigateUp, 0.dp) { MyScaffold(R.string.create_user, onNavigateUp, 0.dp) {
OutlinedTextField( OutlinedTextField(
userName, { userName= it }, Modifier.fillMaxWidth().padding(horizontal = HorizontalPadding), userName, { userName= it }, Modifier.fillMaxWidth().padding(horizontal = HorizontalPadding),
@@ -401,7 +402,7 @@ fun AffiliationIdScreen(
onNavigateUp: () -> Unit onNavigateUp: () -> Unit
) { ) {
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var input by remember { mutableStateOf("") } var input by rememberSaveable { mutableStateOf("") }
val list by affiliationIds.collectAsStateWithLifecycle() val list by affiliationIds.collectAsStateWithLifecycle()
LaunchedEffect(Unit) { getIds() } LaunchedEffect(Unit) { getIds() }
MyScaffold(R.string.affiliation_id, onNavigateUp) { MyScaffold(R.string.affiliation_id, onNavigateUp) {
@@ -440,7 +441,7 @@ fun AffiliationIdScreen(
fun ChangeUsernameScreen(setName: (String) -> Unit, onNavigateUp: () -> Unit) { fun ChangeUsernameScreen(setName: (String) -> Unit, onNavigateUp: () -> Unit) {
val context = LocalContext.current val context = LocalContext.current
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var inputUsername by remember { mutableStateOf("") } var inputUsername by rememberSaveable { mutableStateOf("") }
MyScaffold(R.string.change_username, onNavigateUp) { MyScaffold(R.string.change_username, onNavigateUp) {
OutlinedTextField( OutlinedTextField(
value = inputUsername, value = inputUsername,
@@ -473,8 +474,8 @@ fun UserSessionMessageScreen(
) { ) {
val context = LocalContext.current val context = LocalContext.current
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var start by remember { mutableStateOf("") } var start by rememberSaveable { mutableStateOf("") }
var end by remember { mutableStateOf("") } var end by rememberSaveable { mutableStateOf("") }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
val messages = getMessages() val messages = getMessages()
start = messages.first start = messages.first

View File

@@ -25,6 +25,7 @@ import androidx.compose.material3.Checkbox
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.MenuAnchorType import androidx.compose.material3.MenuAnchorType
@@ -55,7 +56,6 @@ import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.showOperationResultToast import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.CheckBoxItem import com.bintianqi.owndroid.ui.CheckBoxItem
import com.bintianqi.owndroid.ui.CircularProgressDialog import com.bintianqi.owndroid.ui.CircularProgressDialog
import com.bintianqi.owndroid.ui.ExpandExposedTextFieldIcon
import com.bintianqi.owndroid.ui.FullWidthCheckBoxItem import com.bintianqi.owndroid.ui.FullWidthCheckBoxItem
import com.bintianqi.owndroid.ui.FunctionItem import com.bintianqi.owndroid.ui.FunctionItem
import com.bintianqi.owndroid.ui.MyScaffold import com.bintianqi.owndroid.ui.MyScaffold
@@ -301,7 +301,7 @@ fun CrossProfileIntentFilterScreen(
stringResource(direction.text), {}, stringResource(direction.text), {},
Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(), Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(),
label = { Text(stringResource(R.string.direction)) }, readOnly = true, label = { Text(stringResource(R.string.direction)) }, readOnly = true,
trailingIcon = { ExpandExposedTextFieldIcon(dropdown) } trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(dropdown) }
) )
ExposedDropdownMenu(dropdown, { dropdown = false }) { ExposedDropdownMenu(dropdown, { dropdown = false }) {
IntentFilterDirection.entries.forEach { IntentFilterDirection.entries.forEach {

View File

@@ -45,7 +45,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
@@ -102,7 +101,7 @@ fun AppInstaller(
) )
} }
) { paddingValues -> ) { paddingValues ->
var tab by remember { mutableIntStateOf(0) } var tab by rememberSaveable { mutableIntStateOf(0) }
val pagerState = rememberPagerState { 2 } val pagerState = rememberPagerState { 2 }
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
tab = pagerState.targetPage tab = pagerState.targetPage

View File

@@ -2,7 +2,6 @@ package com.bintianqi.owndroid.ui
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@@ -10,10 +9,8 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.ime
import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
@@ -23,7 +20,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material.icons.outlined.Info import androidx.compose.material.icons.outlined.Info
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Card import androidx.compose.material3.Card
@@ -51,7 +47,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@@ -60,6 +55,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.Dialog
import com.bintianqi.owndroid.HorizontalPadding import com.bintianqi.owndroid.HorizontalPadding
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.adaptiveInsets
import com.bintianqi.owndroid.zhCN import com.bintianqi.owndroid.zhCN
@Composable @Composable
@@ -313,7 +309,7 @@ fun MyScaffold(
scrollBehavior = sb scrollBehavior = sb
) )
}, },
contentWindowInsets = WindowInsets.ime contentWindowInsets = adaptiveInsets()
) { paddingValues -> ) { paddingValues ->
Column( Column(
modifier = Modifier modifier = Modifier
@@ -345,7 +341,7 @@ fun MyLazyScaffold(
scrollBehavior = sb scrollBehavior = sb
) )
}, },
contentWindowInsets = WindowInsets.ime contentWindowInsets = adaptiveInsets()
) { paddingValues -> ) { paddingValues ->
LazyColumn(Modifier.fillMaxSize().padding(paddingValues), content = content) LazyColumn(Modifier.fillMaxSize().padding(paddingValues), content = content)
} }
@@ -367,7 +363,7 @@ fun MySmallTitleScaffold(
colors = TopAppBarDefaults.topAppBarColors(colorScheme.surfaceContainer) colors = TopAppBarDefaults.topAppBarColors(colorScheme.surfaceContainer)
) )
}, },
contentWindowInsets = WindowInsets.ime contentWindowInsets = adaptiveInsets()
) { paddingValues -> ) { paddingValues ->
Column( Column(
modifier = Modifier modifier = Modifier
@@ -382,15 +378,6 @@ fun MySmallTitleScaffold(
} }
} }
@Composable
fun ExpandExposedTextFieldIcon(active: Boolean) {
val degrees by animateFloatAsState(if(active) 180F else 0F)
Icon(
imageVector = Icons.Default.ArrowDropDown, contentDescription = null,
modifier = Modifier.rotate(degrees)
)
}
@Composable @Composable
fun ErrorDialog(message: String?, onDismiss: () -> Unit) { fun ErrorDialog(message: String?, onDismiss: () -> Unit) {
if(!message.isNullOrEmpty()) AlertDialog( if(!message.isNullOrEmpty()) AlertDialog(