mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-23 11:05:59 +00:00
Use main NavHost to navigate across all pages
Upgrade dependencies Upload dependencies to GitHub in workflow
This commit is contained in:
@@ -18,20 +18,16 @@ import androidx.annotation.StringRes
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.ScrollState
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material3.AlertDialog
|
||||
@@ -39,9 +35,7 @@ import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme.typography
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -55,7 +49,6 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
@@ -65,106 +58,56 @@ import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.bintianqi.owndroid.R
|
||||
import com.bintianqi.owndroid.fileUriFlow
|
||||
import com.bintianqi.owndroid.getFile
|
||||
import com.bintianqi.owndroid.parseTimestamp
|
||||
import com.bintianqi.owndroid.toggle
|
||||
import com.bintianqi.owndroid.ui.Animations
|
||||
import com.bintianqi.owndroid.ui.CardItem
|
||||
import com.bintianqi.owndroid.ui.CheckBoxItem
|
||||
import com.bintianqi.owndroid.ui.FunctionItem
|
||||
import com.bintianqi.owndroid.ui.InfoCard
|
||||
import com.bintianqi.owndroid.ui.ListItem
|
||||
import com.bintianqi.owndroid.ui.SubPageItem
|
||||
import com.bintianqi.owndroid.ui.MyScaffold
|
||||
import com.bintianqi.owndroid.ui.SwitchItem
|
||||
import com.bintianqi.owndroid.ui.TopBar
|
||||
import com.bintianqi.owndroid.uriToStream
|
||||
import com.bintianqi.owndroid.yesOrNo
|
||||
|
||||
@Composable
|
||||
fun UserManage(navCtrl: NavHostController) {
|
||||
val localNavCtrl = rememberNavController()
|
||||
val backStackEntry by localNavCtrl.currentBackStackEntryAsState()
|
||||
val scrollState = rememberScrollState()
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopBar(backStackEntry, navCtrl, localNavCtrl) {
|
||||
if(backStackEntry?.destination?.route == "Home" && scrollState.maxValue > 100) {
|
||||
Text(
|
||||
text = stringResource(R.string.users),
|
||||
modifier = Modifier.alpha((maxOf(scrollState.value-30, 0)).toFloat() / 80)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
NavHost(
|
||||
navController = localNavCtrl, startDestination = "Home",
|
||||
enterTransition = Animations.navHostEnterTransition,
|
||||
exitTransition = Animations.navHostExitTransition,
|
||||
popEnterTransition = Animations.navHostPopEnterTransition,
|
||||
popExitTransition = Animations.navHostPopExitTransition,
|
||||
modifier = Modifier.padding(top = it.calculateTopPadding())
|
||||
) {
|
||||
composable(route = "Home") { Home(localNavCtrl, scrollState) }
|
||||
composable(route = "UserInfo") { CurrentUserInfo() }
|
||||
composable(route = "Options") { Options() }
|
||||
composable(route = "UserOperation") { UserOperation() }
|
||||
composable(route = "CreateUser") { CreateUser() }
|
||||
composable(route = "EditUsername") { Username() }
|
||||
composable(route = "ChangeUserIcon") { UserIcon() }
|
||||
composable(route = "UserSessionMessage") { UserSessionMessage() }
|
||||
composable(route = "AffiliationID") { AffiliationID() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Home(navCtrl: NavHostController,scrollState: ScrollState) {
|
||||
fun Users(navCtrl: NavHostController) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val deviceOwner = context.isDeviceOwner
|
||||
val profileOwner = context.isProfileOwner
|
||||
//var logoutDialog by remember { mutableStateOf(false) }
|
||||
var dialog by remember { mutableIntStateOf(0) }
|
||||
Column(modifier = Modifier.fillMaxSize().verticalScroll(scrollState)) {
|
||||
Text(
|
||||
text = stringResource(R.string.users),
|
||||
style = typography.headlineLarge,
|
||||
modifier = Modifier.padding(top = 8.dp, bottom = 5.dp, start = 16.dp)
|
||||
)
|
||||
SubPageItem(R.string.user_info, "", R.drawable.person_fill0) { navCtrl.navigate("UserInfo") }
|
||||
MyScaffold(R.string.users, 0.dp, navCtrl) {
|
||||
FunctionItem(R.string.user_info, "", R.drawable.person_fill0) { navCtrl.navigate("UserInfo") }
|
||||
if(deviceOwner && VERSION.SDK_INT >= 28) {
|
||||
SubPageItem(R.string.secondary_users, "", R.drawable.list_fill0) { dialog = 1 }
|
||||
SubPageItem(R.string.options, "", R.drawable.tune_fill0) { navCtrl.navigate("Options") }
|
||||
FunctionItem(R.string.secondary_users, "", R.drawable.list_fill0) { dialog = 1 }
|
||||
FunctionItem(R.string.options, "", R.drawable.tune_fill0) { navCtrl.navigate("UserOptions") }
|
||||
}
|
||||
if(deviceOwner) {
|
||||
SubPageItem(R.string.user_operation, "", R.drawable.sync_alt_fill0) { navCtrl.navigate("UserOperation") }
|
||||
FunctionItem(R.string.user_operation, "", R.drawable.sync_alt_fill0) { navCtrl.navigate("UserOperation") }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 24 && deviceOwner) {
|
||||
SubPageItem(R.string.create_user, "", R.drawable.person_add_fill0) { navCtrl.navigate("CreateUser") }
|
||||
FunctionItem(R.string.create_user, "", R.drawable.person_add_fill0) { navCtrl.navigate("CreateUser") }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 28 && profileOwner && dpm.isAffiliatedUser) {
|
||||
SubPageItem(R.string.logout_current_user, "", R.drawable.logout_fill0) { dialog = 2 }
|
||||
FunctionItem(R.string.logout_current_user, "", R.drawable.logout_fill0) { dialog = 2 }
|
||||
}
|
||||
if(deviceOwner || profileOwner) {
|
||||
SubPageItem(R.string.change_username, "", R.drawable.edit_fill0) { navCtrl.navigate("EditUsername") }
|
||||
FunctionItem(R.string.change_username, "", R.drawable.edit_fill0) { navCtrl.navigate("ChangeUsername") }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 23 && (deviceOwner || profileOwner)) {
|
||||
SubPageItem(R.string.change_user_icon, "", R.drawable.account_circle_fill0) { navCtrl.navigate("ChangeUserIcon") }
|
||||
FunctionItem(R.string.change_user_icon, "", R.drawable.account_circle_fill0) { navCtrl.navigate("ChangeUserIcon") }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 28 && deviceOwner) {
|
||||
SubPageItem(R.string.user_session_msg, "", R.drawable.notifications_fill0) { navCtrl.navigate("UserSessionMessage") }
|
||||
FunctionItem(R.string.user_session_msg, "", R.drawable.notifications_fill0) { navCtrl.navigate("UserSessionMessage") }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 26 && (deviceOwner || profileOwner)) {
|
||||
SubPageItem(R.string.affiliation_id, "", R.drawable.id_card_fill0) { navCtrl.navigate("AffiliationID") }
|
||||
FunctionItem(R.string.affiliation_id, "", R.drawable.id_card_fill0) { navCtrl.navigate("AffiliationID") }
|
||||
}
|
||||
Spacer(Modifier.padding(vertical = 30.dp))
|
||||
LaunchedEffect(Unit) { fileUriFlow.value = Uri.parse("") }
|
||||
}
|
||||
if(dialog != 0 && VERSION.SDK_INT >= 28) AlertDialog(
|
||||
@@ -208,11 +151,11 @@ private fun Home(navCtrl: NavHostController,scrollState: ScrollState) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Options() {
|
||||
fun UserOptions(navCtrl: NavHostController) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) {
|
||||
MyScaffold(R.string.options, 0.dp, navCtrl) {
|
||||
if(VERSION.SDK_INT >= 28) {
|
||||
SwitchItem(R.string.enable_logout, "", null, { dpm.isLogoutEnabled }, { dpm.setLogoutEnabled(receiver, it) })
|
||||
}
|
||||
@@ -220,17 +163,14 @@ private fun Options() {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CurrentUserInfo() {
|
||||
fun CurrentUserInfo(navCtrl: NavHostController) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
|
||||
val user = Process.myUserHandle()
|
||||
var infoDialog by remember { mutableIntStateOf(0) }
|
||||
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) {
|
||||
Spacer(Modifier.padding(vertical = 10.dp))
|
||||
Text(text = stringResource(R.string.user_info), style = typography.headlineLarge)
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
MyScaffold(R.string.user_info, 8.dp, navCtrl) {
|
||||
if(VERSION.SDK_INT >= 24) CardItem(R.string.support_multiuser, UserManager.supportsMultipleUsers().yesOrNo)
|
||||
if(VERSION.SDK_INT >= 31) CardItem(R.string.headless_system_user_mode, UserManager.isHeadlessSystemUserMode().yesOrNo) { infoDialog = 1 }
|
||||
Spacer(Modifier.padding(vertical = 8.dp))
|
||||
@@ -247,7 +187,6 @@ private fun CurrentUserInfo() {
|
||||
}
|
||||
CardItem(R.string.user_id, (Binder.getCallingUid() / 100000).toString())
|
||||
CardItem(R.string.user_serial_number, userManager.getSerialNumberForUser(Process.myUserHandle()).toString())
|
||||
Spacer(Modifier.padding(vertical = 30.dp))
|
||||
}
|
||||
if(infoDialog != 0) AlertDialog(
|
||||
text = { Text(stringResource(R.string.info_headless_system_user_mode)) },
|
||||
@@ -261,7 +200,7 @@ private fun CurrentUserInfo() {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun UserOperation() {
|
||||
fun UserOperation(navCtrl: NavHostController) {
|
||||
val context = LocalContext.current
|
||||
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
|
||||
val dpm = context.getDPM()
|
||||
@@ -287,10 +226,7 @@ private fun UserOperation() {
|
||||
} catch(_: Exception) {
|
||||
false
|
||||
}
|
||||
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) {
|
||||
Spacer(Modifier.padding(vertical = 10.dp))
|
||||
Text(text = stringResource(R.string.user_operation), style = typography.headlineLarge)
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
MyScaffold(R.string.user_operation, 8.dp, navCtrl) {
|
||||
OutlinedTextField(
|
||||
value = idInput,
|
||||
onValueChange = {
|
||||
@@ -365,13 +301,12 @@ private fun UserOperation() {
|
||||
Text(stringResource(R.string.delete))
|
||||
}
|
||||
InfoCard(R.string.info_user_operation)
|
||||
Spacer(Modifier.padding(vertical = 30.dp))
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Composable
|
||||
private fun CreateUser() {
|
||||
fun CreateUser(navCtrl: NavHostController) {
|
||||
val context = LocalContext.current
|
||||
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
|
||||
val dpm = context.getDPM()
|
||||
@@ -379,10 +314,7 @@ private fun CreateUser() {
|
||||
val focusMgr = LocalFocusManager.current
|
||||
var userName by remember { mutableStateOf("") }
|
||||
val flags = remember { mutableStateListOf<Int>() }
|
||||
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) {
|
||||
Spacer(Modifier.padding(vertical = 10.dp))
|
||||
Text(text = stringResource(R.string.create_user), style = typography.headlineLarge)
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
MyScaffold(R.string.create_user, 8.dp, navCtrl) {
|
||||
OutlinedTextField(
|
||||
value = userName,
|
||||
onValueChange = { userName= it },
|
||||
@@ -423,13 +355,12 @@ private fun CreateUser() {
|
||||
}
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
if(newUserHandle != null) { Text(text = stringResource(R.string.serial_number_of_new_user_is, userManager.getSerialNumberForUser(newUserHandle))) }
|
||||
Spacer(Modifier.padding(vertical = 30.dp))
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Composable
|
||||
private fun AffiliationID() {
|
||||
fun AffiliationID(navCtrl: NavHostController) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
@@ -441,10 +372,7 @@ private fun AffiliationID() {
|
||||
list.addAll(dpm.getAffiliationIds(receiver))
|
||||
}
|
||||
LaunchedEffect(Unit) { refreshIds() }
|
||||
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) {
|
||||
Spacer(Modifier.padding(vertical = 10.dp))
|
||||
Text(text = stringResource(R.string.affiliation_id), style = typography.headlineLarge)
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
MyScaffold(R.string.affiliation_id, 8.dp, navCtrl) {
|
||||
Column(modifier = Modifier.animateContentSize()) {
|
||||
if(list.isEmpty()) Text(stringResource(R.string.none))
|
||||
for(i in list) {
|
||||
@@ -483,21 +411,17 @@ private fun AffiliationID() {
|
||||
Text(stringResource(R.string.apply))
|
||||
}
|
||||
InfoCard(R.string.info_affiliated_id)
|
||||
Spacer(Modifier.padding(vertical = 30.dp))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Username() {
|
||||
fun ChangeUsername(navCtrl: NavHostController) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val focusMgr = LocalFocusManager.current
|
||||
var inputUsername by remember { mutableStateOf("") }
|
||||
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) {
|
||||
Spacer(Modifier.padding(vertical = 10.dp))
|
||||
Text(text = stringResource(R.string.change_username), style = typography.headlineLarge)
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
MyScaffold(R.string.change_username, 8.dp, navCtrl) {
|
||||
OutlinedTextField(
|
||||
value = inputUsername,
|
||||
onValueChange = { inputUsername= it },
|
||||
@@ -527,7 +451,7 @@ private fun Username() {
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Composable
|
||||
private fun UserSessionMessage() {
|
||||
fun UserSessionMessage(navCtrl: NavHostController) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
@@ -539,10 +463,7 @@ private fun UserSessionMessage() {
|
||||
end = dpm.getEndUserSessionMessage(receiver)?.toString() ?: ""
|
||||
}
|
||||
LaunchedEffect(Unit) { refreshMsg() }
|
||||
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) {
|
||||
Spacer(Modifier.padding(vertical = 10.dp))
|
||||
Text(text = stringResource(R.string.user_session_msg), style = typography.headlineLarge)
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
MyScaffold(R.string.user_session_msg, 8.dp, navCtrl) {
|
||||
OutlinedTextField(
|
||||
value = start,
|
||||
onValueChange = { start= it },
|
||||
@@ -604,13 +525,12 @@ private fun UserSessionMessage() {
|
||||
Text(stringResource(R.string.reset))
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.padding(vertical = 30.dp))
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Composable
|
||||
private fun UserIcon() {
|
||||
fun ChangeUserIcon(navCtrl: NavHostController) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
@@ -623,10 +543,7 @@ private fun UserIcon() {
|
||||
bitmap = BitmapFactory.decodeStream(stream)
|
||||
}
|
||||
}
|
||||
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) {
|
||||
Spacer(Modifier.padding(vertical = 10.dp))
|
||||
Text(text = stringResource(R.string.change_user_icon), style = typography.headlineLarge)
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
MyScaffold(R.string.change_user_icon, 8.dp, navCtrl) {
|
||||
CheckBoxItem(R.string.file_picker_instead_gallery, getContent, { getContent = it })
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
Button(
|
||||
|
||||
Reference in New Issue
Block a user